- 什么是單例模式?
>是開發設計模式(共23種)中的1種
>它可以保證在程序運行過程,一個類只有一個實例(一個對象),而且該實例易於供外界訪問,從而方便地控制了實例個數,並節約系統資源
>使用場合:在整個應用程序中,共享一份資源(這份資源只需要創建初始化1次) - iOS系統中的一些單例
UIApplication(應用程序實例)
NSNotificationCenter(消息中心)
NSFileManager(文件管理)
NSUserDefaults(應用程序設置)
NSURLCache(請求緩存)
NSHTTPCookieStorage(應用程序cookies池) - 單例模式的基本實現
1.懶漢模式
// 1.在該類中定義一個靜態的全局變量,防止被外部用extren訪問
static id _instance;
/**
static : 修飾變量
1> 修飾全局變量
* 全局變量的作用域僅限於當前文件內部,其他文件不能用extren關鍵字訪問
2> 修飾局部變量 :
* 局部變量的生命周期 跟 全局變量 類似
* 但是不能改變作用域
* 能保證局部變量永遠只初始化1次,在程序運行過程中,永遠只有1分內存
*/
/** * 2.重寫它這個類的llocWithZone:方法,確保只為你這個類分配一次內存地址 * alloc方法內部會調用這個方法 */ + (id)allocWithZone:(struct _NSZone *)zone { if (_instance == nil) { // 防止頻繁加鎖 @synchronized(self) { // 加鎖,避免在多線程中出錯而創建多個對象 if (_instance == nil) { // 防止創建多次 _instance = [super allocWithZone:zone]; } } } return _instance; } // 3.提供一個shared方法讓外界調用這個單例(一般單例都會提供這個方法),確保只init一次 + (instancetype)sharedMusicTool { if (_instance == nil) { // 防止頻繁加鎖 @synchronized(self) { if (_instance == nil) { // 防止創建多次 _instance = [[self alloc] init]; } } } return _instance; } // 4.重寫copyWithZone:方法,避免使用copy時創建多個對象 - (id)copyWithZone:(NSZone *)zone { return _instance; }
2.餓漢模式(當類加載到OC運行環境中(內存)時,就會調用一次生成這個單例(一個類只會加載一次))
// 1.在該類中定義一個靜態的全局變量,防止被外部用extren訪問 static id _instance; /** * 2.重寫它這個類的llocWithZone:方法,這里不用加鎖,因為程序剛啟動,線程還沒加載,不會出現線程不安全的問題 */ + (id)allocWithZone:(struct _NSZone *)zone { if (_instance == nil) { // 防止創建多次 _instance = [super allocWithZone:zone]; } return _instance; } // 3.提供一個shared方法讓外界調用這個單例(一般單例都會提供這個方法) + (instancetype)sharedMusicTool { return _instance; } // 4.重寫copyWithZone:方法,避免使用copy時創建多個對象 - (id)copyWithZone:(NSZone *)zone { return _instance; } // 5.重寫load這個類方法,在里面alloc它 // 這個方法在程序啟動,加載類的時候會調用一次 + (void)load { _instance = [[self alloc] init]; }
- 用GCD實現單例模式
// 1. static id _instance; /** * 2.用GCD的dispatch_once方法重寫 */ + (id)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } // 3. + (instancetype)sharedMusicTool { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } // 4. - (id)copyWithZone:(NSZone *)zone { return _instance; }
- 非ARC下的單例模式
// 前面與ACR一樣,接着重寫以下方法
// 不做release- (oneway void)release { } // retain之后還是自己一份 - (id)retain { return self; } // 計數器永遠為1 - (NSUInteger)retainCount { return 1; } // 防止被放進自動計數池釋放 - (id)autorelease { return self; }
- 用宏定義實現單例(適配ARC和MRC)
// 新建一個.h文件或pch文件,把一下代碼copy進去。在需要實現單例的類中import進去並使用宏(括號里面傳相應的類名)即可
// 在.h文件使用的宏定義 #define HJSingletonH(name) + (instancetype)shared##name; #if __has_feature(objc_arc) // 當前的編譯器環境是ARC // 在.m文件使用的宏定義 #define HJSingletonM(name) \ static id _instace; \ \ + (id)allocWithZone:(struct _NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instace = [super allocWithZone:zone]; \ }); \ return _instace; \ } \ \ + (instancetype)shared##name \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instace = [[self alloc] init]; \ }); \ return _instace; \ } \ \ - (id)copyWithZone:(NSZone *)zone \ { \ return _instace; \ } #else // 當前的編譯器環境是MRC // 在.m文件使用的宏定義 #define HJSingletonM(name) \ static id _instace; \ \ + (id)allocWithZone:(struct _NSZone *)zone \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instace = [super allocWithZone:zone]; \ }); \ return _instace; \ } \ \ + (instancetype)shared##name \ { \ static dispatch_once_t onceToken; \ dispatch_once(&onceToken, ^{ \ _instace = [[self alloc] init]; \ }); \ return _instace; \ } \ \ - (id)copyWithZone:(NSZone *)zone \ { \ return _instace; \ } \ - (oneway void)release {} \ - (id)retain {return self;} \ - (NSUInteger)retainCount {return 1;} \ - (id)autorelease {return self;} #endif