这里和互联网上的其他答案都非常好,但我认为也应该提到这个小细节:
dispatch_once
的优点在于其高度优化,一旦运行后就会消除代码,这种方式我几乎无法理解,但我比较确信这比设置和检查(真实的)全局标记要快得多。
虽然在 Swift 中可以合理地实现标记方法,但需要声明另一个存储的布尔值并不是很好。更不用说线程不安全了。正如文档所述,您应该使用“惰性初始化的全局变量”。是啊,但是为什么要在全局范围内混杂呢?
除非有人能说服我更好的方法,否则我倾向于在我将要使用它的范围内或者接近该范围内声明我的 do-once 闭包,如下所示:
private lazy var foo: Void = {
}()
基本上我是在说“当我读到这句话时,foo
应该是运行这个代码块的结果。” 它的行为方式与全局let
常量完全相同,只不过在正确的作用域内。而且看起来更漂亮。然后我可以在任何地方调用它,通过将其读入永远不会被使用的变量中。我喜欢Swift中的_
。像这样:
_ = foo
这个很酷的小技巧早已存在,但并没有得到太多关注。它基本上会在运行时将变量保留为未调用的闭包,直到有东西想要查看其
Void
结果。在读取时,它调用闭包,丢弃它并将其结果保留在
foo
中。
Void
在内存方面实际上几乎不使用,所以后续读取(例如
_ = foo
)对CPU不造成任何影响。(别引用我说的话,请有人检查汇编是否正确!)你可以有很多这样的变量,Swift在第一次运行后就几乎不再关心它们了!抛弃那个旧的
dispatch_once_t
,让你的代码像圣诞节开箱时一样漂亮!
我的一个问题是,在第一次读取之前,您可以将
foo
设置为其他内容,然后您的代码将永远不会被调用!因此需要使用全局的
let
常量来防止这种情况发生。问题是,类作用域中的常量与
self
不兼容,因此不能使用实例变量……但说真的,您什么时候将任何东西设置为
Void
呢?
此外,您需要将返回类型指定为
Void
或
()
,否则它仍会抱怨
self
。谁能想到呢?
而
lazy
只是为了使变量像它应该的那样懒惰,这样Swift就不会在
init()
上直接运行它。
相当时髦,只要记得不要写入它就可以了!:P
private
添加到类的构造函数中不是很好吗?请注意,如果在此类中有一个变量,您可能会有多个实例保持对该变量的不同值。一旦构造函数是private
的,只有static let singleton
行才能初始化它。 - henriquedispatch_once
块中使用实例变量怎么办? - Inder Kumar Rathore