为什么“didset”在设置属性的属性时会调用属性?

在这段代码中当文本改变时, titleEditingChanged被调用(如预期的那样)。 但是当它执行该行时

 investment?.title = sender.text! 

它调用了Investmentdidset{} 。 为什么?

 class InvestmentCell: UITableViewCell { var investment: Investment? { didSet { // setup UI elements from class properties textField.text = investment?.title valueField.text = investment?.value?.description } } @IBAction func titleEditingChanged(sender: UITextField) { investment?.title = sender.text! } @IBOutlet weak var textField: UITextField! @IBOutlet weak var valueField: UITextField! } 

这是因为Investment可能是一个结构,而不是一个阶级。 在Swift中,结构体是值types的,而不是类的引用types。 所以,结构不是“可变的”。

这意味着每当你改变一个struct属性时,一个新的struct对象被分配来replace当前的对象数据,当前的对象数据被复制到新的结构对象中,除了包含新值集的改变的属性。

请记住,只要使用let命令初始化一个结构对象(使用一个类就可以),编译器不会让你改变结构属性。

这就解释了为什么每当你改变struct属性的时候就会调用观察者。 一旦一个新的结构对象被分配来replace当前的结构对象,它将被存储在另一个内存块中,所以它的值将被改变, didSet观察者将被调用。

PS:如果您将“ Investment定义为类而不是结构,则不会发生这种情况。

当types实例的底层属性被设置时, 值types的属性观察者(例如结构)也被调用; 只是因为实例本身值被更新了 。 同样不适用于参考types ; 只要引用本身没有变异,属性观察者就不会被调用(即引用本身可以被认为是引用types的值)。

从语言指南 – 属性 -我们阅读的属性观察者 :

物业观察员观察并回应物业价值的变化 。 每次属性值设置时都会调用属性观察器,即使新值与属性的当前值相同


要validation上述内容,请考虑以下示例:

 /* reference type */ class InvestmentC { var title: String = "Foo" } /* value type */ struct InvestmentS { var title: String = "bar" } class InvestmentContainer { var investmentC : InvestmentC { didSet { print("did set a property of 'InvestmentC' instance (ref. type)") } } var investmentS : InvestmentS { didSet { print("did set a property of 'InvestmentS' instance (val. type)") } } init() { investmentC = InvestmentC() investmentS = InvestmentS() } } /* Example: property observer called only when setting a property of the value type instance 'investmentC' */ let foo = InvestmentContainer() foo.investmentC.title = "foobar" // prints: nothing foo.investmentS.title = "foobar" // prints: "did set a property of 'InvestmentS' instance (val. type)" 

因此,我们可以推断出你的自定义typesInvestment是一个值types(一个结构),并且即使你只设置/更新了这个types的实例investment (在你的UITableViewCell子类中)的didSet属性observer, investment 。 如果您想避免这种情况, didSet Investment更改为引用types(类),在这种情况下,只有investment实例本身已设置/更新,才会更改didSet属性观察器。