再谈Singleton
我们现在用Objective-C实作Singleton的时候,大概都是按照Mike Ash的建议—参见Friday Q&A 2009-10-02: Care and Feeding of Singletons─使用GCD里头的dispatch_once
实作。大概像这样:
@interface MyClass : NSObject
+ (instancetype) sharedInstance;
@end
@implementation MyClass
+ (instancetype) sharedInstance
{
static MyClass *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[MyClass alloc] init];
});
return instance;
}
@end
之所以这么写的原因,是为了避免在多重thread 的环境下,shared instance 可能会被重复建立的问题。我们来看如果只用if 语法实作的singleton:
@implementation MyClass
+ (instancetype) sharedInstance
{
static MyClass *instance = nil;
if (!instance) {
instance = [[MyClass alloc] init];
}
return instance;
}
@end
在instance这个变数还没有建立的状况下,假如就已经有多个thread同时进入了前面这段程式的if判断式当中,那么,每个进入这段程式的thread,都会分别执行到instance = [[MyClass alloc] init];
这一行,而重复建立instance。我们对于Singleton物件的要求是:这个Class只会建立一个instance,在所有地方呼叫+sharedInstance
,也都只该拿到同一个物件,但是在这种写法中,不同thread呼叫+sharedInstance
,就可能会拿到不同的物件。
由于dispatch_once
里头的block只会执行一次,我们便透过这个特性,保证instance = [[MyClass alloc] init];
只会被呼叫到一次。