比较这两个用于定义实例属性的选项:
var networkManager = NetworkManager.sharedInstance()
var lazy networkManager = NetworkManager.sharedInstance()
这两种:
懒:
非懒:
似乎使用非惰性变量没有任何好处。那么为什么语言允许程序员做出这种低劣的选择呢?
(我不是在询问var和let la la Are Swift constants lazy by default?之间的区别)
答案 0 :(得分:9)
一个原因可能是懒惰不适合在评估发生时需要控制的情况。这与在任务中完成的工作有副作用的情况相关。
虽然这与clojure有关,但stuart sierra的这篇博客post很好地解释了这个想法,我认为它同样适用于任何语言。
答案 1 :(得分:7)
正如其他人已经说过的,有几个关键场景,你希望属性的初始化是确定性的。
这是与游戏开发相关的一个示例(与众不同)。
通常,代表游戏场景/关卡中的项目的类的实例是在<+>之前创建的。
初始化可能是一项耗时的任务(从持久存储中加载内容,分配内存,准备实例......)并且在播放器开始播放级别之前执行此部分确实可以避免 CPU开销
这很关键,因为在一个级别中间的CPU开销可能会导致帧速率下降,这对用户体验来说是一场噩梦。
答案 2 :(得分:5)
随着时间的推移,FYI。我的感觉是,Swift希望变得更像一种功能性语言,并希望在更多地方进行懒惰的实例化。
My early assessment of Swift已经相当不错了(好吧,“非功能性”部分。我没想到Swift会在以后的版本中使用多少方法而不是函数)。 Swift不是一种功能语言,也不打算成为一种语言。这经常出现在WWDC会谈,论坛,推特以及与Swift团队的对话中。最初所有的地图和过滤器都是懒惰的。 Swift删除了它,因为它引起的问题。可能关于该主题的最佳谈话是"Building Better Apps with Value Types in Swift"。正如他们所说:
我们喜欢变异。我们认为它很有价值。我们认为正确完成后很容易使用。
你没有比这更“无功能”。 Swift还拥抱不可变数据。但函数式编程是关于不可变数据的纯函数,而不是Swift。
(当然有很多非懒惰的函数式语言。懒惰和功能都是正交概念.Haskell碰巧接受了两者。)
对于手头的问题,但是:
我发现lazy
属性在现实世界的Swift中很少有用(我很慷慨;我从未遇到过我将其保存在代码中的情况)。它没有提供像你在Haskell中得到的懒惰。 It isn't thread safe,所以这是一场噩梦。它强迫你进入引用类型(或强制你的结构是可变的),这样可能很烦人。如果我听说他们是从语言中拉出来的话我们只是不得不自己动手,那对我来说没关系。 (我很想写一个提案来做到这一点。)它实现了一个特定的备忘录模式,偶尔可以派上用场,但往往不是你想要的。所以它不是默认值,这是一件非常好的事情。
正如您可能知道的那样,默认情况下,全局变量和类变量 是懒惰的,而且我认为这种方法很容易解决,因为它们的数量要少得多,因此它们的可能性要大得多在实践中不会被访问,并且懒惰是线程安全的(这有成本,但因为它们非常罕见,所以成本要低得多)。
答案 3 :(得分:0)
如果您有一个昂贵的对象(就创建而言需要很长时间),您可以决定并控制何时创建它。有人可能会认为懒惰变量应该是默认变量。也许它有历史原因。 ObjC中的惰性属性产生了很多样板代码。
答案 4 :(得分:0)
lazy var
不是线程安全的。您可以使用dispatch_once
,常数(let
)或嵌套结构模式(通常用于单例)来确保线程安全。您也可以使用NSRecursiveLock
来使用自己的锁定,但是效率可能不如dispatch_once
。
似乎并非所有lazy
变量都保证在多线程环境中被初始化一次。您需要对其进行显式编程,或者使用静态属性。
尽管延迟加载可以帮助开发人员减少内存占用, 避免将太多数据加载到内存中,甚至避免工作 某种初始化或设置问题(例如设置视图) 当您需要访问自己而不是自己的实例时 初始化)。但是,并不总是应用延迟加载 免费电话:有时您需要加倍努力以避免 副作用。最后,不要害怕延迟变量。它仍然是 可以帮助您实现其存在的奇妙事物。 干杯!