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 willSetoldValuefor 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 내가 사용하는 단순화 된 예제를 추가 한 getset
마이크 Rapadas

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

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

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