Swift 프로그래밍 : 저장된 속성의 getter / setter


102

Swift에서 저장된 속성의 setter를 어떻게 덮어 쓰나요?

Obj-C에서는 setter를 덮어 쓸 수 있지만 Swift는 저장된 속성에 사용되는 getter / setter에 만족하지 않는 것 같습니다.

Card라는 속성 이있는 클래스가 있다고 가정 해 보겠습니다 rank. 클라이언트가 잘못된 값을 제공하는 것을 원하지 않으므로 Objective-C에서 덮어 써서 setRank추가 검사를 수행 할 수 있습니다 . 그러나 willSetSwift에서는 newValue상수 이기 때문에 도움이되지 않는 것 같고 ranksetter가 루프에서 호출되기 때문에 할당하는 것은 의미가 없습니다 .


이렇게하는 방법을 찾았습니까? 나도 이런 종류의 기능이 필요합니다 ...
— Mihai Fratu

찾았어요. ... 내 대답을 확인하십시오
— 미하이 Fratu에게

didGet 또는 아날로그는 어떻습니까?
— fnc12

답변:


107

확인. Swift에 대한 Apple 문서를 읽으면서 다음을 발견 했습니다 .

자신의 didSet 관찰자 내의 속성에 값을 할당하면 할당 한 새 값이 방금 설정 한 값을 대체합니다.

그래서 당신이해야 할 일은 다음과 같습니다.

var rank: Int = 0 {
    didSet {
        // Say 1000 is not good for you and 999 is the maximum you want to be stored there
        if rank >= 1000  {
            rank = 999
        }
    }
}

didGet 또는 아날로그는 어떻습니까?
— fnc12

귀하의 질문을 이해하지 못했습니다. 좀 더 구체적으로 말씀해 주시겠습니까?
— Mihai Fratu

가져 오기 전에 몇 가지 코드를 호출해야합니다. 나는 이것을 obj-c에서 수행 할 수 있었지만 Swift에서 이것을 수행하는 방법을 볼 수 없습니다. 내가 보는 유일한 것은 두 개의 속성을 사용하는 것입니다. 하나는 public이고 다른 하나는 private이고, public은 내 코드를 호출하고 private 속성의 값을 반환합니다. 내가 didGet에 대해 질문하는 이유입니다
— fnc12

계산 된 속성에 대한 getter 만 가질 수 있습니다. 예를 들어var rankTimesTwo: Int { get { return rank * 2 } }
— 미하이 Fratu

2
매력처럼 작동합니다! 초기화에서 속성 () 설정시는 호출되지 않습니다주의
— 크리스토프

35

저장된 속성에 대해 get/ set를 재정의 할 수는 없지만 속성 관찰자 willSet/를 사용할 수 있습니다 didSet.

var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
}

기본 매개 변수 이름은 newValuefor willSet및 oldValuefor didSet이거나 에서 와 같이 직접 이름을 지정할 수 있습니다 willSet(newTotalSteps).


작동합니다. 그러나 내 문제를 해결하지 못하거나 원래 질문에서 충분히 명확하지 않았을 수 있습니다.
— bohanl

Card라는 속성 이있는 클래스가 있다고 가정 해 보겠습니다 rank. 나는 클라이언트가 어떤 값도 부여하지 않기를 원하므로 Objective-C에서 덮어 쓸 수 setRank있으므로 추가 검사를 수행합니다. 그러나 willSetSwift에서는 newValue상수 이기 때문에 도움이되지 않는 것 같고 ranksetter가 루프에서 호출되기 때문에 할당하는 것은 의미가 없습니다 .
— bohanl

2
나는 당신이 무엇을 의미하는지 완전히 확신하지 못하지만 설정 후 didSet확인 하는 데 사용할 수 없으며 rank유효성 검사에 실패하면 다른 것으로 재설정하십시오 oldValue.
— 조셉 마크

9

get 및 set는 계산 된 속성 용입니다 (백업 저장소가 없음). (제 생각에는 'var'라는 키워드가 여기에서 혼란 스럽습니다)

  • willSet 및 didSet은 인스턴스 변수에 대해 호출됩니다 (변경 사항을 무시하려면 didSet 사용)
  • set 및 get은 순전히 계산 된 속성을위한 것입니다.

9

속성 값이 일시적으로 잘못되었다는 문제가있는 didSet을 사용하지 않으려면 계산 된 속성을 그 주위에 래핑해야합니다.

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        if(newValue > 999) {
            _foo = 999
        } else {
            _foo = newValue
        }
    }
}

또는:

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        guard newValue <= 999 else {
            _foo = 999
            return
        }
        _foo = newValue
    }
}

두 개의 변수를 사용하는 것은 의미가 없습니다.
— Piyush

1
이것은 단지 하나의 속성 (변수)을 사용하는 것입니다 : foo단지 계산 된 표현입니다 _foo. "var"키워드가 당신을 속이게하지 마십시오! 이는 private 네임 스페이스에서 액세스 할 수있는 두 개의 항목이 있지만 protected / public과 관련이 없으며 foo항상 valid 값을 유지한다는 것을 의미합니다 . 이것은 본질적으로 "보기"패턴입니다. 를 통해 재 작성할 때 발생하는 문제 didSet는 유효하지 않은 기간이있을뿐만 아니라 didSet내부 에서 핸들러를 다시 입력하기 때문에 무한 루프가 발생할 가능성이 크다는 것 didSet입니다.
— Jim Driscoll

-8

단순화 된 예 :

class Shape {
    var sideLength: Double {
    get {
        return self.sideLength
    }
    set {
        // Implement the setter here.
        self.sideLength = newValue
    }
    }
}

전체 예

perimeter이 예에서 확인하십시오 .

발췌 : Apple Inc.“The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l

class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) {
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
    get {
        return 3.0 * sideLength
    }
    set {
        sideLength = newValue / 3.0
    }
    }

    override func simpleDescription() -> String {
        return "An equilateral triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength”

3
이 perimeter경우은 여전히 ​​계산 된 속성입니다. 계산 된 속성을 도입하지 않고 sideLength를 어떻게 덮어 쓰나요?
— bohanl

@bohanl 내가 사용하는 단순화 된 예제를 추가 한 get과set
— 마이크 Rapadas

6
"전체 예제"는 저장된 속성이 아닌 계산 된 속성을 표시하며 "단순 예제"가 작동하지 않습니다.
— Caleb

나는 바로 잡았다. 마치 Objective-C에서 @property (자동 합성 게터 + 세터)의 추상화가 Swift에서 추상화되지 않은 것과 같습니다. 아이러니 ...
— 마이크 Rapadas

6
"간단한 예"는 자체 게터 내에서 게터를 호출하는 것입니다. Inf 루프 ... 충돌.
— jakenberg 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.