本文由CocoaChina译者leon(社区ID)翻译
原文:THE RIGHT WAY TO WRITE A SINGLETON
在之前的帖子里聊过状态管理有多痛苦,有时这是不可避免的。一个状态管理的例子大家都很熟悉,那就是单例。使用Swift时,有许多方法实现单例,这是个麻烦事,因为我们不知道哪个最合适。这里我们来回顾一下单例的历史,看一看在Swift中如何正确地实现单例。
如果你想直接看看Swift中单例的正确实现方式,直接跳到帖子最后即可。
往事回忆之ObjC单例
Swift是Objective-C的一种自然演变,它用如下的方式实现单例:
@interface Kraken : NSObject
@end
@H_502_57@@implementation Kraken
+ (instancetype)sharedInstance {
static Kraken *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken,^{
sharedInstance = [[Kraken alloc] init];
});
return
sharedInstance;
}
@end
在这个现成方案中,我们可以看到单例的基本结构。让我们来约定一些规则,这样便于更好的理解。
单例规则
关于单例,有三个重要的准则需要牢记:
1. 单例必须是唯一的(要不怎么叫单例?) 在程序生命周期中只能存在一个这样的实例。单例的存在使我们可以全局访问状态。例如:
NSNotificationCenter,UIApplication和NSUserDefaults。
2. 为保证单例的唯一性,单例类的初始化方法必须是私有的。这样就可以避免其他对象通过单例类创建额外的实例。
3. 考虑到规则1,为保证在整个程序的生命周期中值有一个实例被创建,单例必须是线程安全的。并发有时候确实挺复杂,简单说来,如果单例的代码不正确,如果有两个线程同时实例化一个单例对象,就可能会创建出两个单例对象。也就是说,必须保证单例的线程安全性,才可以保证其唯一性。通过调用dispatch_once,即可保证实例化代码只运行一次。
在程序中保持单例的唯一性,只初始化一次,这样并不难。帖子的余下部分中,需要记住:单例实现要满足隐藏的dispatch_once规则。
Swift单例
自Swift 1.0开始,创建单例有很多种方法。这些链接中已经有很详尽的描述,比如
https://github.com/hpique/SwiftSingleton,http://stackoverflow.com/questions/24024549/dispatch-once-singleton-model-in-swift和
https://developer.apple.com/swift/blog/?id=7。但是谁喜欢点链接呢?先剧透一下吧:总共有4个版本。我们来清点一下:
1. 最丑陋方法(Swift皮,Objective-C心)
class TheOneAndOnlyKraken {
class
var
sharedInstance: TheOneAndOnlyKraken {
struct Static {
static
var
onceToken: dispatch_once_t = 0
@H_502_57@
static
var
instance: TheOneAndOnlyKraken? = nil
}