web-dev-qa-db-ja.com

Swiftでは、didSet内のプロパティをリセットすると別のdidSetがトリガーされますか?

私はこれをテストしていますが、didSet内の値を変更すると、didSetへの別の呼び出しが行われないようです。

var x: Int = 0 {
    didSet {
        if x == 9 { x = 10 }
    }
}

これは信頼できますか?どこかに文書化されていますか? Swift Programming Languageのドキュメントには記載されていません。

16
Rob N

私もこれは不可能だと思いました(多分それはSwift 2に含まれていなかったかもしれません)が、それをテストして見つけた where Appleはこれを使用します(「タイププロパティのクエリと設定」で)

struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int = 0 {
        didSet {
            if currentLevel > AudioChannel.thresholdLevel {
                // cap the new audio level to the threshold level
                currentLevel = AudioChannel.thresholdLevel
            }
            if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                // store this as the new overall maximum input level
                AudioChannel.maxInputLevelForAllChannels = currentLevel
            }
        }
    }
}

そして、このコードの下に、次のメモがあります。

これら2つのチェックの最初のチェックでは、didSetオブザーバーがcurrentLevelを別の値に設定します。 これはできません、しかし、オブザーバーが再び呼び出される原因になります

14
FelixSFD

Apple docs (私の強調)から:

同様に、didSetオブザーバーを実装すると、古いプロパティ値を含む定数パラメーターが渡されます。パラメータに名前を付けるか、oldValueのデフォルトのパラメータ名を使用できます。 独自のdidSetオブザーバー内のプロパティに値を割り当てる場合、割り当てた新しい値は、設定されたばかりの値を置き換えます。

したがって、didSetでの値の割り当ては公式には問題なく、無限再帰はトリガーされません。

6
FreeNickname

これは問題なく動作しますが、APIのコンシューマーの観点からはかなり悪い考えのようです。

それは私がそれを疑ったように再帰しないので、それは少なくとも良いことです。

セッターが私が設定しているものを変更することが許容されるいくつかのケースを考えることができます。このような例の1つは、角度に設定された変数であり、[0, 2π]に自動的に正規化されます。