单例三要素
- 唯一性:在一个应用程序的生命周期中,只有一个实例存在。单例提供了一个唯一的全局状态,例如:NSNotification,UIApplication和NSUserDefaults
- 构造器私有:为了保证单例的唯一性,构造器必须私有,防止其他对象也能创建出单例类的实例
- 线程安全:确保单例在整个应用程序的生命周期中是唯一的,防止两个线程在同一时间初始化同一个单例,这样就有潜在的风险得到两个不同的单例。使用GCD的dispatch_once来确保初始化单例的代码在运行时只执行一次
OC
+ (instancetype)sharedDataCenter {
static KCDataCenter *dataCenter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dataCenter = [[KCDataCenter alloc] init];
});
return dataCenter;
}
Swift
最优雅的写法
如果你深谙单例三要素,相信这种写法你很容易接收
class KCDataCenter {
static let sharedDataCenter = KCDataCenter()
private init() {}
}
演变过程
照搬OC写法
class KCDataCenter {
class var sharedDataCenter: KCDataCenter {
struct Static {
static var onceToken : dispatch_once_t = 0
static var dataCenter : KCDataCenter? = nil
}
dispatch_once(&Static.onceToken) {
static.dataCenter = KCDataCenter()
}
return Static.dataCenter!
}
}
结构体写法
class KCDataCenter {
class var sharedDataCenter : KCDataCenter {
struct Static {
static let dataCenter = KCDataCenter()
}
return Static.dataCenter
}
}
全局变量写法
中文校对版中这里有一处错误,详解请看原文
private let dataCenter = KCDataCenter()
class KCDataCenter {
class var sharedDataCenter : KCDataCenter {
return dataCenter
}
}
private保证线程安全
“全局变量(静态成员变量和结构体以及枚举)的延迟构造器在其被第一次访问时会加载,并以dispatch_once的方式启动来确保初始化的原子性。这让你写代码时可以用一种很酷的方式来使用dispatch_once:直接用一个全局变量的构造器去做初始化并用private来修饰。“ — Apple’s Swift Blog
接下来就是最优雅的写法
class KCDataCenter {
static let sharedDataCenter = KCDataCenter()
private init() {}
}