單例模式是開發者經常使用的一種設置模式,常見的實現方式爲:在類中編寫名爲 sharedInstance的方法,該方法只會返回全類共用的單例實例,而不會在每次調用時建立新的實例.安全
常見的作法是:函數
+ (instancetype)sharedUser { static User *_sharedInstance = nil; @synchronized(self) { if (!_sharedInstance) { _sharedInstance = [[self alloc] init]; } } return _sharedInstance; }
爲了保證線程安全,上面的代碼把建立代理的代碼包裹在同步塊裏. spa
相對於上面的實現方式,使用GCD的dispatch_once實現起來更爲容易. 所用到的函數是:線程
static dispatch_once_t onceToken;代理
dispatch_once(&onceToken, ^{code
// code to be executed oncetoken
});作用域
此函數接受的類型爲 dispatch_once_t的特殊函數 token,此外還接受塊參數.對於給定的token來講,該函數保證相關的塊一定會執行,且僅執行一次.首次調用該函數時必然會執行塊中的代碼,最重要的是:次操做徹底是線程安全的!!!須要注意的是:對於只需執行一次的塊來講,每次調用函數時傳入的token必須徹底相同.因此一般將token標記聲明在static或者global做用域裏.開發
使用GCD實現單例方法以下:字符串
+ (instancetype)sharedUser{ static User *_shareInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!_shareInstance) { _shareInstance = [[self alloc] init]; } }); return _shareInstance; }
使用dispatch_once能夠簡化代碼而且實現線程安全,所以你無需擔憂加鎖或者同步的問題.全部問題都有GCD在底層處理.因爲每次調用時都必須使用徹底相同的token,因此token須要聲明爲static. 把token聲明在static做用內,能夠保證編譯器每次執行shareUser方法時都會複用這個變量,而不會建立新的變量.
此外,dispatch_once更高效. 他沒有使用重量級的加鎖機制,若是是使用加鎖的話,每次運行代碼前都要獲取鎖,相反 dispatch_once 函數採用原子訪問來查詢token,以判斷對應的代碼是否已經執行過.
--> 使用 dispathch_once 能夠輕鬆編寫 "只需運行一次的線程安全代碼",能夠輕鬆實現單例.
--> token 應該聲明在static或者golbal做用域中,這樣的話吧只需執行一次的塊傳給dispatch_once函數時,能夠保證傳進去的token也是相同的.
附贈一份快速實現單例的 .h 文件
調用以下:
1.導入 Singleton.h文件
2.在類的.h文件中 singleton_h(單例的名字),以User類舉例,單例的名字會自動拼接上 shared
#import <Foundation/Foundation.h> #import "Singleton.h" @interface User : NSObject singleton_h(User); @end #import "User.h" @implementation User singleton_m(User); @end
3.調用
User *user = [User sharedUser];
// ## : 鏈接字符串和參數 #define singleton_h(name) + (instancetype)shared##name; #if __has_feature(objc_arc) // ARC #define singleton_m(name) \ static id _instance; \ + (id)allocWithZone:(struct _NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \ } \ \ + (instancetype)shared##name \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc] init]; \ });\ return _instance; \ } \ + (id)copyWithZone:(struct _NSZone *)zone \ { \ return _instance; \ } #else // 非ARC #define singleton_m(name) \ static id _instance; \ + (id)allocWithZone:(struct _NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \ } \ \ + (instancetype)shared##name \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc] init]; \ }); \ return _instance; \ } \ \ - (oneway void)release \ { \ \ } \ \ - (id)autorelease \ { \ return _instance; \ } \ \ - (id)retain \ { \ return _instance; \ } \ \ - (NSUInteger)retainCount \ { \ return 1; \ } \ \ + (id)copyWithZone:(struct _NSZone *)zone \ { \ return _instance; \ } #endif
------------------
文獻參考:<編寫高質量OSX和iOS代碼的52個有效方法>