使用由另一个属性支持的计算属性比在Swift中使用lazy
修饰符更安全吗?
// method 1: using LAZY variable
lazy var myVar:Int {
// assume that this calculation takes
// a lot of time and resources
return 5
}
现在考虑Apple的Swift 2(预发布)中的以下引用:
请注意
如果标有
lazy
修饰符的属性被多个访问 线程同时并且属性尚未初始化, 无法保证该物业只会被初始化一次。
就个人而言,我一直在做自己的懒惰"像这样的逻辑:
考虑替代方法:
// method 2: using calculated property backed by another property
var myVar:Int? {
if self._myVar != nil {
return self._myVar
}
let aVar:Int = 5 // assume this is done after exhaustive calcuation
self._myVar = aVar
return self._myVar
}
var _myVar:Int? = nil
使用(方法2),我能保证"详尽的计算"只会被执行一次?
答案 0 :(得分:4)
您建议的方法2不保证lazy
没有的任何内容。
// method 2: using calculated property backed by another property var myVar:Int? { if self._myVar != nil { return self._myVar } let aVar:Int = 5 // assume this is done after exhaustive calcuation self._myVar = aVar return self._myVar } var _myVar:Int? = nil
此外,它还有一个额外的缺陷,即可选而非非可选。作为一个隐式展开的可选项,这会稍微好一点,所以我们不必连续打开它。
而且,我们无法设置myVar
。加_myVar
应该是私密的。
但问题是你没有将初始化代码锁定为同步。
假设您有线程A开始访问myVar
。 if self._myVar != nil
检查返回false,因此我们不会返回self._myVar
。现在我们进入详尽的计算。
现在,在详尽的计算完成之前,线程B尝试访问myVar
。由于线程A尚未完成详尽的计算,if self._myVar != nil
仍然返回false,现在线程B进行详尽的计算。
基本上,这就是lazy
关键字给你的同样问题....但是当lazy
已经足够时,你写了很多代码来做到这一点。