iOS開發實踐之多線程(單例模式)
單例模式的作用:可以保證在程式運行過程,一個類只有一個執行個體,而且該執行個體易於供外界訪問,從而方便地控制了執行個體個數,並節約系統資源。
單例模式的使用場合: 在整個應用程式中,共用一份資源(這份資源只需要建立初始化1次)。
一:單例模式 - ARC:
1、在.m中保留一個全域的static的執行個體(static 防止其它類extern引用 修改值)
static id _instance;
2、重寫allocWithZone:方法,在這裡建立唯一的執行個體(注意安全執行緒)
+ (id)allocWithZone:(struct _NSZone *)zone {
if (_instance == nil) { // 防止頻繁加鎖
@synchronized(self) {
if (_instance == nil) { // 防止建立多次
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}
3、提供1個類方法讓外界訪問唯一的執行個體
+ (instancetype)sharedMusicTool {
if (_instance == nil) { // 防止頻繁加鎖
@synchronized(self) {
if (_instance == nil) { // 防止建立多次
_instance = [[self alloc] init];
}
}
}
return _instance;
}
4、實現copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone {
return _instance;
}
5、如果要實現餓漢式的單例,就實現load方法。(建議不使用)
//當類載入到OC運行時環境中(記憶體),就會調用一次(一個類只會載入1次)
+(void)load{
_instance = [[self alloc] init];
}
音樂單例工具類例子代碼:
MusicTool.h
#import @interface MusicTool : UIView//提供1個類方法讓外界訪問唯一的執行個體+(instancetype)sharedMusicTool;@end
MusicTool.m
#import "MusicTool.h"//單例模式:懶漢式@implementation MusicToolstatic id _instance; //static 防止其它類extern引用 修改值/** * 如果要實現餓漢式的單例,就實現load方法 * 當類載入到OC運行時環境中(記憶體),就會調用一次(一個類只會載入1次) *///+(void)load{// _instance = [[self alloc] init];//}//當第一次使用這個類的時候才會調用//+(void)initialize{// NSLog(@"===initialize===");//}/** * alloc 方法內部會調用這個方法 */+(id)allocWithZone:(struct _NSZone *)zone{ if (_instance == nil) {//防止頻繁加鎖 @synchronized(self) { if (_instance == nil) {//防止建立多次 _instance = [super allocWithZone:zone]; } } } return _instance;}/** * 執行個體化類 */+(instancetype)sharedMusicTool{ if (_instance == nil) {//防止頻繁枷鎖 @synchronized(self) { if (_instance == nil) {//防止建立多次 _instance = [[self alloc] init ]; } } } return _instance;}/** * 重寫copy方法,保證copy出來的也是單例類 */-(id)copyWithZone:(NSZone *)zone{ return _instance;}@end
二:單例模式 – 非ARC
非ARC中(MRC),單例模式的實現(比ARC多了幾個步驟)
實現記憶體管理方法
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1; }
- (oneway void)release {}
- (id)autorelease { return self; }
MusicTool.m
#import "MusicTool.h"@implementation MusicToolstatic id _instance; //static 防止其它類extern引用 修改值/** * 如果要實現餓漢式的單例,就實現load方法 * 當類載入到OC運行時環境中(記憶體),就會調用一次(一個類只會載入1次) *///+(void)load{// _instance = [[self alloc] init];//}//當第一次使用這個類的時候才會調用//+(void)initialize{// NSLog(@"===initialize===");//}/** * alloc 方法內部會調用這個方法 */+(id)allocWithZone:(struct _NSZone *)zone{ if (_instance == nil) {//防止頻繁加鎖 @synchronized(self) { if (_instance == nil) {//防止建立多次 _instance = [super allocWithZone:zone]; } } } return _instance;}/** * 執行個體化類 */+(instancetype)sharedMusicTool{ if (_instance == nil) {//防止頻繁枷鎖 @synchronized(self) { if (_instance == nil) {//防止建立多次 _instance = [[self alloc] init ]; } } } return _instance;}/** * 重寫copy方法,保證copy出來的也是單例類 */-(id)copyWithZone:(NSZone *)zone{ return _instance;}//重寫release方法,不釋放-(oneway void)release{ }//重寫retain方法,返回單例類-(instancetype)retain{ return self; //return _instance;}//計算永遠為1-(NSUInteger)retainCount{ return 1;}@end
測試:
MusicTool *mt1 = [[MusicTool alloc] init]; MusicTool *mt2 = [MusicTool sharedMusicTool]; MusicTool *mt3 = [mt2 copy]; [mt2 release];//非arc環境下release NSLog(@"==%@==%@==%@",mt1,mt2,mt3);
三:單例模式在ARC\MRC環境下的寫法有所不同,可以用宏判斷是否為ARC環境
#if __has_feature(objc_arc)
// ARC
#else
// MRC
#endif
把單例定義成宏,抽出公用類
1、HMSingleton.h
// .h檔案#define HMSingletonH(name) + (instancetype)shared##name;// .m檔案#if __has_feature(objc_arc) #define HMSingletonM(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 #define HMSingletonM(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
2、要想再整個項目中都能使用這個宏,則要在先行編譯pch檔案中import匯入這個標頭檔
#ifdef __OBJC__
#import
#import
#import "HMSingleton.h"
#endif
3、使用HMSingleton工具類,實現HMMusicTool單例
HMMusicTool.h
#import @interface HMMusicTool : NSObject//宏定義的方法HMSingletonH(MusicTool)@end
HMMusicTool.m
#import "HMMusicTool.h"@implementation HMMusicTool//宏定義的方法HMSingletonM(MusicTool)@end
4.測試:
HMMusicTool *tool1 = [HMMusicTool sharedMusicTool]; HMMusicTool *tool2 = [HMMusicTool sharedMusicTool]; HMMusicTool *tool3 =[[HMMusicTool alloc]init]; HMMusicTool *tool4 =[tool3 copy]; NSLog(@"%@", tool1); NSLog(@"%@", tool2); NSLog(@"%@", tool3); NSLog(@"%@", tool4);