Thousand Squared

希望能分享一些學習心得啊啊啊~~~.

Singletons in Cocoa/Objective-C

| Comments

什麼是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檔。

SingletonClass.h
1
2
3
@interface SingletonClass : NSObject
+ (SingletonClass *)sharedInstance;
@end
SingletonClass.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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:

SingletonClass.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@implementation SingletonClass

+ (id)sharedInstance
{
    static SingletonClass *sharedMyInstance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedMyInstance = [[super allocWithZone:nil] init];
    });

    return sharedMyInstance;
}
@end

+ (id)allocWithZone:(NSZone *)zone
{
    return [self sharedInstance];
}

官方文件檔對dispatch_once的解釋:

Executes a block object once and only once for the lifetime of an application.

方法2是目前最簡單也最安全,也是常在WWDC影片中看到的方法。

結論:

如果真的要用singleton,那就使用第二種方法吧!

參考資料:

  1. Singleton - Cocoa Core Competencies.
  2. Creating a Singleton Instance - Cocoa Fundamentals Guide.
  3. Singletons in Cocoa/Objective-C
  4. Singletons: You’re doing them wrong

Comments