IOS開發之單例設計模式,IOS開發之設計模式
本文將從四個方面對IOS開發中的單例設計模式進行講解:
一、什麼是單例設計模式二、我們為什麼要用單例設計模式三、單例設計模式的基本用法四、自訂單例設計模式代碼的封裝
一、什麼是單例設計模式
所謂單例,即是單個的執行個體化對象,保證一個類有且僅有一個執行個體。通常情況下,當我們對一個類執行個體化時(如:alloc、new等),並不能保證每次執行個體化的對象是唯一的執行個體。那麼為了保證該類可在多次執行個體化的過程中保證記憶體位址不變,就需要引入單例設計模式。
二、我們為什麼要用單例設計模式
1、Singleton 會阻止其他對象執行個體化其自己的 Singleton 對象的副本,從而確保所有對象都訪問唯一執行個體,如手機中有多個音樂播放器,但需要為使用者播放最後開啟的播放器中的音樂,為提高使用者體驗,這種播放工具類就需要用單例來實現。
2、可提高安全執行緒,在執行個體化單例時我們用到了一個dispatch_once函數
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
該函數在整個程式的聲明周期中,僅執行一次某一個block對象,系統已經幫我們加了鎖,所以在多個線程搶奪同一資源的時候,他也是安全的
三、單例設計模式的基本用法
通常情況下,一般的單例設計模式只需要重寫兩個方法即可,當然需要用來執行個體化對象的share或standard的類方法是必要的。
+ (id)allocWithZone:(NSZone *)zone;// IOS9.0之後不需要引入NSCopying對copyWithZone方法重寫也不會報錯- (id)copyWithZone:(NSZone *)zone;
實現單例的類方法:
static id _instance;+ (instancetype)shareAudioPlayer { /** 一次性執行 dispatch_once是安全的,系統已經幫我們加了鎖,所以在多個線程搶奪同一資源的時候,他也是安全的 */ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"---once---"); _instance = [[self alloc] init]; }); return _instance;}
對以上兩個方法的重寫
+ (instancetype)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; }- (id)copyWithZone:(NSZone *)zone { return _instance;}
單例設計模式在ARC與非ARC下的內部機制後有一些不同,下面我們分別就兩種記憶體管理員模式對單例設計模式進行說明。
如果在ARC下,上面的代碼便足夠實現單例設計模式,以下代碼不需重寫。
如果在MRC下,則在重寫以上兩個方法的基礎上,還要對下面的四個方法進行重寫:
- (id)retain;- (NSUInteger)retainCount;- (void)release;- (id)autorelease;
// MRC下還要重寫以下方法- (oneway void)release {}- (instancetype)retain {return _instance;}- (instancetype)autorelease {return _instance;}- (NSUInteger)retainCount {return 1;}
以上即為單例設計模式在ARC或MRC下的用法。如果需要同時相容MRC或ARC就需要對縮寫代碼進行判斷,我們一般用條件編譯來進行判斷:
#if __has_feature(objc_arc) // ARC NSLog(@"MRC下插入ARC代碼也是可以的,在MRC下也不會報錯,但不會被執行");#else // MRC NSLog(@"ARC下插入MRC代碼也是可以的,在ARC下也不會報錯,但不會被執行");#endif
四、自訂單例設計模式代碼的封裝
在我們工作過程中,如果需要自訂單例設計模式,以上代碼難免會重複編寫,為了提高工作效率,可考慮將代碼進行封裝
singleton_h(DBTool)singleton_m(DBTool)/** 單例抽取成宏,只需要改兩個部分,一個是.h檔案裡面的內容,一個是.m檔案裡面的內容 宏裡面拼接參數用兩個 ## */// .h檔案單獨抽取#define singleton_h(name) \+ (instancetype)share##name;#if __has_feature(objc_arc) // ARC環境下#define singleton_m(name) \static id _instance; \\+ (instancetype)share##name { \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [[self alloc] init]; \}); \return _instance; \} \\+ (instancetype)allocWithZone:(struct _NSZone *)zone { \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [super allocWithZone:zone]; \}); \return _instance; \} \\- (id)copyWithZone:(NSZone *)zone { \return _instance; \} #else // 非ARC環境下(MRC)#define singleton_m(name) \static id _instance; \\+ (instancetype)share##name { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [[self alloc] init]; \ }); \ return _instance; \} \\+ (instancetype)allocWithZone:(struct _NSZone *)zone { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instance = [super allocWithZone:zone]; \ }); \ return _instance; \} \\- (id)copyWithZone:(NSZone *)zone { \ return _instance; \} \\- (oneway void)release {} \- (instancetype)retain {return _instance;} \- (instancetype)autorelease {return _instance;} \- (NSUInteger)retainCount {return 1;}#endif
如果本文有任何錯誤之處,歡迎拍磚指正,共同進步, 謝謝!