迅速なプログラミング:格納されたプロパティのゲッター/セッター


102

Swiftに保存されているプロパティのセッターを上書きするにはどうすればよいですか?

Obj-Cでは、セッターを上書きできますが、Swiftは、保存されたプロパティにゲッター/セッターが使用されていることに満足していないようです。

Cardと呼ばれるプロパティを持つクラスがあるとしますrank。クライアントに無効な値を与えたくないので、objective-Cでは、setRank追加のチェックを実行するように上書きできます。しかしwillSet、SwiftではnewValueは定数であるため役に立たないようでありrank、setterがループで呼び出されるため、割り当てることは意味がありません。


これを行う方法を見つけましたか?私はこの種の機能を自分で必要としています...
Mihai Fratu 2014年

見つけた。私の答えを確認してください...
Mihai Fratu 2014年

didGetまたはアナログはどうですか?
fnc12

回答:


107

OK。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でこれを実行する方法がわかりません。私が目にする唯一のことは、2つのプロパティを使用することです。1つはパブリックで、もう1つはプライベートです。パブリックがコードを呼び出し、プライベートプロパティの値を返します。それが、didGetについて質問した理由です
fnc12

計算プロパティにはゲッターしか設定できません。例var rankTimesTwo: Int { get { return rank * 2 } }
Mihai Fratu

2
魅力的な作品!init()でプロパティを設定するときに呼び出されないことに注意してください
Christoph

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 2014年

Cardと呼ばれるプロパティを持つクラスがあるとしますrank。クライアントに値を与えたくないので、objective-Cでは上書きsetRankして、追加のチェックを実行します。しかしwillSet、SwiftではnewValueは定数であるため役に立たないようでありrank、setterがループで呼び出されるため、割り当てることは意味がありません。
bohanl 2014年

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
    }
}

2つの変数を使用しても意味がありません。
Piyush、

1
これは、1つのプロパティ(変数)のみを使用しています。これはのfoo計算式にすぎ_fooません。「var」キーワードに騙されないでください。これは、プライベート名前空間からアクセス可能な2つのエントリがあることを意味しますが、それはprotected / publicには影響せずfoo、常に有効な値を保持します。これは基本的に「ビュー」パターンです。無効な期間があることに加えて、を介した書き換えで発生する問題didSetdidSet、内からハンドラーを再入力しているため、無限ループになる可能性が非常に高いことですdidSet
Jim Driscoll、2018年

-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 2014年

私が使用して簡単な例を追加しました@bohanl getset
マイクRapadas

6
「完全な例」は、格納されたプロパティではなく、計算されたプロパティを示し、「簡略化された例」は機能しません。
カレブ2014年

私は修正された立場です。Objective-Cの@property(自動合成ゲッター+セッター)の抽象化がSwiftで抽象化されていないかのようです。皮肉...
マイク・ラパダス2014年

6
あなたは「単純化された例」は、それ自身のゲッター内でゲッターを呼び出すことです。INFループ...クラッシュ。
jakenberg 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.