單例(singleton)
-
意圖
- 保證一個(gè)類僅有一個(gè)實(shí)例黔龟,并提供一個(gè)訪問它的全局訪問點(diǎn)同衣。
-
適用性
- 當(dāng)類只能有一個(gè)實(shí)例而且客戶可以從一個(gè)眾所周知的訪問點(diǎn)訪問它
- 當(dāng)這個(gè)唯一的實(shí)例應(yīng)該是通過子類化可以擴(kuò)展的晨汹,并且客戶應(yīng)該無需更改代碼就能使用一個(gè)擴(kuò)展的實(shí)例時(shí)
-
結(jié)構(gòu)
-
優(yōu)缺點(diǎn)
- 對(duì)唯一實(shí)例的受控訪問
- 縮小命名空間
- 允許對(duì)操作和表示的精化
- 允許可變數(shù)目的實(shí)例
- 比類操作更加靈活
-
實(shí)現(xiàn)
- OC版本
// 非線程安全 @interface Singleton: NSObject +(instancetype)sharedInstance; @end @implementation Singleton static Singleton* instance = nil; // 程序運(yùn)行時(shí)就初始化該單例 //+(void)load { // [Singleton sharedInstance]; //} +(instancetype)sharedInstance { if(instance == nil){ instance = [[Singleton alloc] init]; } return instance; } //當(dāng)我們調(diào)用alloc時(shí)候回調(diào)改方法(保證唯一性)镜撩,oc不允許構(gòu)造方法私有化 +(id)allocWithZone:(struct _NSZone *)zone { if(instance == nil){ instance = [super allocWithZone:zone]; } return instance; } @end // 線程安全 @implementation Singleton static Singleton* instance = nil; +(instancetype)sharedInstance { if(instance == nil) { // 加鎖解鎖是需要消耗性能的 @synchronized (self) { if(instance == nil) { instance = [[Singleton alloc] init]; } } } return instance; } +(id)allocWithZone:(struct _NSZone *)zone { @synchronized (self) { if(instance == nil) { instance = [super allocWithZone:zone]; } } return instance; } @end // 線程安全-GCD @implementation Singleton static Singleton* instance = nil; +(instancetype)sharedInstance { static dispatch_once_t once; dispatch_once(&once, ^{ instance = [[Singleton03 alloc] init]; }); return instance; } // 2017.8.10 更新旧巾,這里的做法是不對(duì)的房资,原因請(qǐng)看下文 //當(dāng)我們調(diào)用alloc時(shí)候回調(diào)改方法(保證唯一性)蜕劝,oc不允許構(gòu)造方法私有化 +(id)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t once; dispatch_once(&once, ^{ instance = [super allocWithZone:zone]; }); return instance; } @end
華麗的分割線,感覺慧慧大神指出 OC 版單例的一處錯(cuò)誤轰异,上面所以說的用 allocWithZone 來保持唯一性的做法不是太合理岖沛,應(yīng)該直接禁用 alloc 和 init 方法:
+ (id)alloc NS_UNAVAILABLE; - (instancetype) init NS_UNAVAILABLE;
- Swift版本
// 非線程安全 final class Singleton: NSObject { private static var instance: Singleton? = nil class func sharedInstance() -> Singleton { if instance == nil { instance = Singleton() } return instance! } // 將構(gòu)造方法私有化 private override init() { } } // 線程安全 final class Singleton: NSObject { static var sharedInstance = Singleton() private override init() { } }
對(duì)于如何選擇線程安全或者非線程安全的單例呢,如果程序不涉及多線程時(shí)搭独,就優(yōu)先選擇非線程安全吧婴削,畢竟加鎖解鎖還是需要消耗資源的。