什麼是Singleton?
在程式設計中,singleton是常常被使用的design pattern。
依照官方文件來解釋,它的意思是說:
A singleton class returns the same instance no matter how many times an application requests it.
如果你建立了一個 singleton class,當你在呼叫此 class 的 instance 時,它永遠會回傳相同的 instance。這樣的好處在於,你不會建立無用的 instance,不浪費記憶體,也不會產生錯誤的資料,在 application 中永遠都使用同一筆資料。
建立Singleton
依照官方的建議 Creating a Singleton Instance
嚴格定義一個 singleton class,你必須要斷絕使用者任何可能產生錯誤的步驟。
方法1:
我們建立一個SingletonClass,實作它的.h與.m檔。
@interface SingletonClass : NSObject
+ (SingletonClass *)sharedInstance;
@end
@implementation SingletonClass
+ (id)sharedInstance
{
static SingletonClass *sharedMyInstance = nil;
if (!sharedMyInstance) {
sharedMyInstance = [[super allocWithZone:nil] init];
}
return sharedMyInstance;
}
@end
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
此方法主要利用static
的概念實作:一個變數被宣告成 static,此變數不會隨著 method 結束而被銷毀。更進一步的說,static 變數只會被宣告一次,而且永遠不會被銷毀。而當你把一個 static 變數宣告在 method 裡時,只有此 method 才可以呼叫此 static 變數。
照上面的例子來看,只有sharedInstance
這個method可以呼叫sharedMyInstance
。此外當第二次遇到static SingletonClass *sharedMyInstance = nil;
時,程式會發現,已經有 sharedMyInstance了,所以就不做任何動作(因為 static 變數無法被銷毀)。
那為什麼要override allocWithZone:
??
Program defensively!!!
因為要防止聰明的 programmer,透過allocWithZone:
產生新的 instance。
當使用者呼叫allocWithZone
時,程式會改呼叫sharedInstance
,判斷是否已經產生sharedMyInstance。這樣就達到singleton的效果!
但是,此種寫法有個致命的缺點,它 不是thread safe,也就是說,當你的 instance 同時被許多的 thread 呼叫時,有可能會爆炸...
如果你一定要用 singleton,就用 dispatch_once() 吧!
方法2:
@implementation SingletonClass
+ (id)sharedInstance
{
static SingletonClass *sharedMyInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyInstance = [[self alloc] initWithSingleton];
});
return sharedMyInstance;
}
@end
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedInstance];
}
- (id)initWithSingleton
{
self = [super init];
if (self)
{
// init your properties
}
}
官方文件檔對 dispatch_once 的解釋:
Executes a block object once and only once for the lifetime of an application.
方法2是目前最簡單也最安全,也是常在WWDC影片中看到的方法。
結論:
如果真的要用singleton,那就使用第二種方法吧!
參考資料:
-
Singleton - Cocoa Core Competencies.
-
Creating a Singleton Instance - Cocoa Fundamentals Guide.
-
Singletons in Cocoa/Objective-C
-
Singletons: You're doing them wrong