这里和互联网周围的其他答案非常好,但我觉得这个小花絮也应该被提及:
最棒的dispatch_once
是它的优化程度,基本上是在第一次运行后以一种我几乎不理解的方式修改代码,但可以合理地保证这比设置和检查(真正的)全局令牌要快得多。
虽然令牌可以在 Swift 中合理地实现,但必须声明另一个存储的布尔值并不是那么好。更不用说线程不安全了。正如文档所说,您应该使用“延迟初始化的全局”。是的,但是为什么要把全局范围弄得乱七八糟,对吧?
在有人说服我有更好的方法之前,我倾向于在我将使用它的范围内或相当接近的范围内声明我的 do-once 闭包,如下所示:
private lazy var foo: Void = {
// Do this once
}()
基本上我是说“当我读到这个时,foo
应该是运行这个块的结果。” 它的行为方式与全局常量完全相同let
,只是在正确的范围内。而且更漂亮。然后我会在任何我喜欢的地方调用它,通过将它读入其他永远不会使用的东西。我喜欢 Swift 的_
。像这样:
_ = foo
这个非常酷的怪癖实际上已经存在了一段时间,但还没有看到太多的爱。它基本上在运行时将变量单独保留,作为未调用的闭包,直到有东西想看到它的Void
结果。在读取时,它调用闭包,将其丢弃并将其结果保存在foo
. Void
在内存方面几乎不使用任何内容,因此后续读取(即_ = foo
)在 CPU 上什么也不做。(不要引用我的话,请有人检查一下程序集以确保!)拥有尽可能多的数量,Swift 在第一次运行后基本上不再关心它!丢掉那个旧的dispatch_once_t
,并让你的很多代码像圣诞节那天第一次打开它时一样漂亮!
我的一个问题是您可以foo
在第一次阅读之前设置其他内容,然后您的代码将永远不会被调用!因此,全局let
常数可以防止这种情况发生。问题是,类范围内的常量不能很好地与self
.Void
那,你需要将返回类型指定为Void
or ()
,否则它仍然会抱怨self
. 谁来敲门?
只是为了让变量尽可能地懒惰,所以lazy
Swift 不会直接在init()
.
很时髦,只要你记得不要给它写信!:P