15 Oct 2017 by 晓晨
文档有说,
You can add property observers to any stored properties you define, except for lazy stored properties. – The Swift Programming Language (Swift 4): Properties
但文档中没有解释为什么要这样,这里我来猜猜看。
首先做个试验,
class SomeClass {
lazy var lazyStoredProperty: Int = {
print("execute expensive computation")
return 42
}()
}
let c = SomeClass()
c.lazyStoredProperty = 0
上面例子中的 lazyStoredProperty,一直没有被访问过,在最后一句中被赋值(不算访问),这个例子的执行结果是什么都不打印,也就是说它的初始值中定义的 closure 一直没有被执行。
可以看出,Swift 在处理 lazy stored properties 时,只要不访问就不求值,对其赋值也不会强制求它的初始值。这样做是合理的,尽其所能避免 lazy stored properties 的初始化求值,因为这可能是一笔很大的开销。
但想象一下,如果 lazy stored properties 允许有 property observers,那当它被赋值时,会调用两个函数,willSet 和 didSet。我们考虑一个 lazy stored property 在定义后一直没有被访问过,当它第一次被赋值时,
在赋值之前,调用 willSet,其实现中可能会访问这个 property 的旧值,这里也就是其初始值,但是因为这是个 lazy stored property,它的初始值此前还没求过,访问这个 property 就会执行对它的初始值求值,从而产生开销,这个求值过程不是代码作者容易意识到的。
赋值之后,调用 didSet,因为该函数实际上接受了一个 oldValue 的参数,这里就是这个 property 的初始值,因为函数传递参数必须先进行求值,所以这里会对其初始值求值。
总的来说,让 lazy stored properties 支持 property observers 后,即便没有访问过一个 property,对其赋值也会造成其初始值求值,但是赋值操作本不需要知道原来的值,这是一笔不必要的开销。