【问题标题】:willSet/didSet called on a container's stored property x when setting a property of xwillSet/didSet 在设置 x 的属性时调用容器的存储属性 x
【发布时间】:2016-10-01 13:28:53
【问题描述】:

我观察到了我不太理解的行为。在操场上执行此代码时:

protocol Testp {
    var notes: String { get set }
}

class Testc: Testp {
    var notes: String = "x"
}

class TestContainer {
    var test: Testp = Testc() {
        willSet {
            print("willSet")
        }
        didSet {
            print("didSet")
        }
    }
}

var testContainer = TestContainer()
print(testContainer.test.notes) // prints "x"

// this triggers a willSet+didSet call on TestContainer's
// stored property, even though "test" is not changed in testContainer
testContainer.test.notes = "y"

print(testContainer.test.notes) // prints "y"

如上所述,即使没有设置属性本身,也会调用 willSetdidSet 块。

另一方面,如果我将协议更改为以下类型的类

protocol Testp: class {
    var notes: String { get set }
}

那么结果就是我所期望的(即没有调用willSet/didSet)。

这种行为的原因是什么?

我在 XCode 7.3 上运行它。

更新:仍在 XCode 9.2 / Swift 4 中

【问题讨论】:

  • 你解决过这个问题吗?看到同样的问题。
  • 我很自私地很高兴终于看到其他人最终陷入了导致问题的境地;)抱歉,但不,除了做事不同之外,我从来没有解决过这个问题。

标签: swift swift-protocols


【解决方案1】:

这是因为Testp 很容易成为classstruct。如果它是struct,那么分配testContainer.test.notes = "y" 将创建一个全新的Testp 实现者实例。另一方面,通过设置protocol Testp: class,您可以明确告诉notes 的分配不会改变test

考虑一个函数

func doSomething(_ container: TestContainer) {
    testContainer.test.notes = "y"
}

你不知道在这个函数内部TestContainer 是如何配置类或结构的。我猜 Swift 团队认为总是加注will/didChange 不会那么令人困惑,因为这种情况是这样的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-22
    • 2019-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 1970-01-01
    • 2014-08-20
    相关资源
    最近更新 更多