虽然入坑时曾经用Swift2.0写过4个多月代码,后来换公司项目又用OC了,现在打算用Swift写代码了. OC->Swift->OC->Swift😂
本想创建一个Struct单例
struct BannerQueue {
static let `default` = BannerQueue()
var banners: [Banner] = []
}
在其他地方多次使用 BannerQueue.default 时发现 banners数组的值不一致,每次都是新建的数组。
查了下网上说结构体是值传递(在栈中),不能创建单例,每次调用都是一个新的对象,类才行(值引用, 在堆中)。
正确的单例方式:
class BannerQueue {
static let `default` = BannerQueue()
private init() {}
}
注意: 必须保证init方法的私有性,只有这样,才能保证单例是真正唯一的,避免外部对象通过访问init方法创建单例类的其他实例。由于Swift中的所有对象都是由公共的初始化方法创建的,我们需要重写自己的init方法,并设置其为私有的。这很简单,而且不会破坏到我们优雅的单行单例方法。
以前在OC中创建单例,会用到dispatch_once,或者直接用OC的直接移植版写Swift单例, 其实没必要的,Swift这一句简洁的代码已经帮我们实现了dispatch_once,原因如下:
现在,你可能会有疑问:为何看不到dispatch_once?根据Apple Swift博客中的说法,以上方法都自动满足dispatch_once规则。这里有个帖子可以证明dispatch_once规则一直在起作用。
“全局变量(还有结构体和枚举体的静态成员)的Lazy初始化方法会在其被访问的时候调用一次。类似于调用'dispatch_once'以保证其初始化的原子性。这样就有了一种很酷的'单次调用'方式:只声明一个全局变量和私有的初始化方法即可。”--来自Apple's Swift Blog
(“The lazy initializer for a global variable (also for static members of structs and enums) is run the first time that global is accessed, and is launched asdispatch_once
to make sure that the initialization is atomic. This enables a cool way to usedispatch_once
in your code: just declare a global variable with an initializer and mark it private.”)这就是Apple官方文档给我们的所有信息,但这些已经足够证明全局变量和结构体/枚举体的静态成员是支持”dispatch_once”特性的。现在,我们相信使用全局变量来“懒包装”单例的初始化方法到dispatch_once代码块中是100%安全的。