引用语言指南 - 属性 - 属性观察者[强调我的]:
物业观察员
属性观察者观察并响应属性值的变化。
...
您可以选择在属性上定义其中一个或两个观察者:
willSet
在存储值之前调用。
didSet
在存储新值后立即调用。
当您正在使用willSet
属性观察器进行试验时,您在willSet
块内观察到的属性的任何突变都在实际存储之前newValue
,紧跟在willSet
块之后。这意味着您实际上是在尝试在将“旧副本”myArr
替换为其新值之前对其进行变异。
可以说这可以被讨论为非法的,因为任何突变都myArr
应该导致任何属性观察者的调用,因此属性观察者中的属性突变(引用类型的引用或值类型的值的突变)可能会导致递归调用属性观察者。然而,情况并非如此,对于这种willSet
情况,特别是会发出警告,正如@vadian 的回答中所指出的那样。在属性观察者中属性本身的突变不会触发属性观察者这一事实并没有得到很好的记录,但是语言指南 - 属性 - 类型属性中的一个示例指出了这一点[强调矿]:
查询和设置类型属性
...
该currentLevel
属性有一个didSet
属性观察器来检查currentLevel
它被设置时的值。...
笔记
在这两个检查中的第一个中,didSet
观察者设置
currentLevel
为不同的值。但是,这不会导致再次调用观察者。
这也是一个我们可以预料到的特殊情况,因为didSet
它是一个很好的地方,可以合并例如将给定属性值限制在某些范围内的边界检查;即,用有界值覆盖新值,以防前者超出范围。
现在,如果您更改为在新值存储后更改属性,则更改将生效,并且如上所述,不会触发对属性观察者的任何额外调用。应用于您的示例:
var myArr = [String]() {
didSet {
print("now count is: \(myArr.count)")
if myArr.count > 2 {
print("now remove all!")
myArr.removeAll()
}
}
}
myArr.append("hello")
myArr.append(",world")
myArr.append("!")
myArr.append("too much.")
print("The content is \(myArr)") // The content is ["too much."]