2017-02-09 5 views
4

もちろん、didSetはdidSet内から同じオブジェクト上で再び実行されないことはよく知られています。 (example内部クラスの保護は奇妙なことにクラス全体に及んでいますか?

ただし、それはそうだ:制限は、そのオブジェクトだけでなく、同じクラスの任意のオブジェクトに適用されます。

ここにはPlaygroundのコピー・ペースト・テスト・ケースがあります。

class C { 
    var Test: Bool = false { 
     didSet { 
      print("test.") 
      for c in r { 
       c.Test = true 
      } 
     } 
    } 
    var r:[C] = [] 
} 
var a:C = C() 
var b:C = C() 
var c:C = C() 
a.r = [b, c] 
a.Test = false 

機能しません!

class C { 
    var Test2: Bool = false { 
     didSet { 
      print("test2.") 
      global.Test2 = true 
     } 
    } 
} 
var global:C = C() 
var a:C = C() 
a.Test2 = false 

動作しません!

  1. これはスウィフトバグですか?

  2. は何ですか? didSetから始まるANY didSet(何でも)は実行されません。同じ同じクラス?同じスーパークラスですか?または?

  3. これはdocoで正確に説明されていますか?

WTF。 1つは知っておく必要があります...特に実際の制限は何ですか?

+0

理論上、子どもの1人はそれ自身である可能性があります。無限ループがまだ発生する可能性があることを意味します。バグかもしれない、機能かもしれないそれは答えではないので、それはコメントにある理由:) – PeejWeej

+1

@JoeBlow:このコメントは[Swiftソースコード](https://github.com/apple/swift/blob /master/lib/AST/Decl.cpp#L1072)が関連している可能性があります:*「観察しているメンバーは、didSet/willSet指定子の中から直接アクセスします。これにより、割り当てが無限ループにならないようにします。 swift-usersメーリングリストでは、Swiftチームのメンバーが定期的に貢献しています。 –

+0

これは同じ質問のように見えます:[なぜ、セットに無限ループがありますか?](http://stackoverflow.com/questions/29363170/why-no-infinite-loop-in-didset) –

答えて

1

これはバグSR-419です。バグにコメントから

うわ。プロパティのアクセスの基底が静的にはselfであることを確認する必要があります。

私の実験から、didSetオブザーバは、どのオブジェクトにも同じプロパティを設定した場合にのみ呼び出されるように思われます。他のプロパティ(同じオブジェクト上であっても)を設定すると、オブザーバが正しく呼び出されます。

class A { 
    var name: String 
    var related: A? 
    var property1: Int = 0 { 
     didSet { 
      print("\(name), setting property 1: \(property1)") 

      self.property2 = 100 * property1 
      related?.property1 = 10 * property1 
      related?.property2 = 100 * property1 
     } 
    } 
    var property2: Int = 0 { 
     didSet { 
      print("\(name), setting property 2: \(property2)") 
     } 
    } 

    init(name: String) { 
     self.name = name 
    } 
} 

let a = A(name: "Base") 
a.related = A(name: "Related") 
a.property1 = 2 

出力:

ベース、設定プロパティを1:2
ベース、設定プロパティ2:200
関連、設定プロパティ2:200

予想出力は:

ベース、設定プロパティを1:2
ベース、プロパティ2設定:200
関連、設定プロパティを1:20
関連、プロパティ2設定:設定2000
関連のプロパティ2:200

オブザーバからを直接に割り当てる必要があるようです。あなたが別の関数(またはオブザーバー)を入力すると、オブザーバーは再び作業を開始:

var property1: Int = 0 { 
    didSet { 
     print("\(name), setting property 1: \(property1)") 

     onSet() 
    } 
} 

...  
func onSet() { 
    self.property2 = 100 * property1 
    related?.property1 = 10 * property1 
    related?.property2 = 100 * property1 
} 

をそして、それは最高の回避策です。

別の回避策(感謝@Hamish)は即座に実行閉鎖にネストされた割り当てをラップすることです:

var property1: Int = 0 { 
    didSet { 
     { 
      self.property2 = 100 * property1 
      related?.property1 = 10 * property1 
      related?.property2 = 100 * property1 
     }() 
    } 
} 

が閉鎖する前に、コードによっては、括弧の中にそれを包むか、前の後にセミコロンを挿入する必要がありますステートメント。

+0

@JoeBlow私のテストでは、無関係のプロパティで正しく動作します。また、 'property1.didSet'から呼び出される' property2.didSet'から 'property1.didSet'を呼び出すと、期待どおりの素敵な無限ループが得られます。私はサブクラスをテストしていませんが、同じように動作すると思います。それはまだ同じプロパティです。 – Sulthan

+1

すぐに実行されるクロージャを使用する別の興味深い回避策: '_ = {self.related?.property1 = 10 * self.property1}()'(何らかの理由でSwiftは ' _ = ')。 – Hamish

+0

@Hamishあなたはvoidを返すためにマニュアルリターンを追加する必要があります:) – Sulthan

関連する問題