單例的概念
單例類保證了應(yīng)用程序的生命周期中有且僅有一個(gè)該類的實(shí)例對(duì)象,而且易于外界訪問。在iOS中有很多單例類,比如UIApplication,UIScreen,NSNotificationCenter,NSFileManager,NSUserDefaults,NSURLCache,NSHTTPCookieStorage等等。
單例模式的使用場(chǎng)合
在整個(gè)應(yīng)用程序中,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次),一般用于工具類。例如:登陸控制器,網(wǎng)絡(luò)數(shù)據(jù)請(qǐng)求,音樂播放器等一個(gè)工程需要使用多次的控制器或方法。
單例模式實(shí)現(xiàn)方法
一、ARC環(huán)境下單例模式的實(shí)現(xiàn)代碼,以Singleton類為例
//.h文件
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
//為了使實(shí)例易于外界訪問 我們一般提供一個(gè)類方法,類方法命名規(guī)范 share類名|default類名|類名
+(instancetype)shareSingleton;
@end
//.m文件
#import "Singleton.h"
@implementation Singleton
//0.提供全局變量
static id _instance;
//1.alloc會(huì)調(diào)用allocWithZone:
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
//實(shí)現(xiàn)單例模式的方法1
/*
//加互斥鎖解決多線程訪問安全問題
@synchronized(self) {
if (_instance == nil) {
_instance = [super allocWithZone:zone];
}
}
*/
//實(shí)現(xiàn)單例模式的方法2:使用GCD提供的一次性代碼
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [super allocWithZone:zone];
});
return _instance;
}
//2. 實(shí)現(xiàn)類方法(單例方法)
+(instancetype)shareSingleton
{
return [[self alloc]init];
}
//3.copy在底層 會(huì)調(diào)用copyWithZone:
//為了嚴(yán)謹(jǐn),也要重寫copyWithZone 和 mutableCopyWithZone
-(id)copyWithZone:(NSZone *)zone
{
return _instance;
}
-(id)mutableCopyWithZone:(NSZone *)zone
{
return _instance;
}
二、MRC環(huán)境下單例模式的實(shí)現(xiàn)代碼
在ARC代碼基礎(chǔ)上重寫下面的三個(gè)方法即可
/*ARC代碼段,詳見上文*/
//什么都不做 保證單例對(duì)象不被銷毀
-(oneway void)release{}
//返回本身 保證只有一個(gè)單例對(duì)象
-(instancetype)retain
{
return _instance;
}
//將引用計(jì)數(shù)設(shè)為最大值(習(xí)慣)
-(NSUInteger)retainCount
{
return MAXFLOAT;
}
三、在ARC和MRC環(huán)境下都適用的單例代碼
利用條件編譯來判斷是ARC還是MRC環(huán)境
在ARC代碼基礎(chǔ)上,利用條件編譯判斷是否重寫下列方法。
/*ARC代碼段,詳見上文*/
#if __has_feature(objc_arc) //如果是ARC環(huán)境,不需要重寫
#else //如果是MRC環(huán)境,則重寫下列代碼
-(oneway void)release{}
-(instancetype)retain{
return _instance;
}
-(NSUInteger)retainCount{
return MAXFLOAT;
}
#endif
四、多個(gè)類可以共同使用的單例代碼(ARC環(huán)境和MRC環(huán)境均適用)
創(chuàng)建文件Single.h(文件名稱不固定),將上面的代碼抽出一個(gè)宏,如下:
/*
1 宏定義后面如果要替換字符,需要用##拼接
2 宏定義后邊如果出現(xiàn)換行,需要用符號(hào)“ \ ” 來標(biāo)記下一行也是宏定義的部分,但最后一行末尾不需要
*/
//.h文件 ##表示拼接字符
#define SingleH(name) +(instancetype)share##name;
#if __has_feature(objc_arc) //條件滿足 ARC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
return _instance;\
}
#else //MRC
#define SingleM(name) static id _instance;\
+(instancetype)allocWithZone:(struct _NSZone *)zone{\
static dispatch_once_t onceToken;\
dispatch_once(&onceToken, ^{\
_instance = [super allocWithZone:zone];\
});\
return _instance;\
}\
+(instancetype)share##name{\
return [[self alloc]init];\
}\
-(id)copyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(id)mutableCopyWithZone:(NSZone *)zone{\
return _instance;\
}\
-(oneway void)release{}\
-(instancetype)retain{\
return _instance;\
}\
-(NSUInteger)retainCount{\
return MAXFLOAT;\
}
#endif
假設(shè)我們要在類Person中使用,調(diào)用方法如下:
1、在項(xiàng)目中導(dǎo)入文件Singel.h。
2、Person類中的代碼
Person.h文件
===========================
#import <Foundation/Foundation.h>
#import "Single.h"
@interface Person
SingleH(Person)
@end
Person.m文件
===========================
#import "Person.h"
@implementation Person.h
SingleM(Person)
@end
注意:
單例模式不可以使用繼承,因?yàn)槭褂美^承,同時(shí)也會(huì)繼承靜態(tài)變量,當(dāng)子類和父類同時(shí)創(chuàng)建的時(shí)候只會(huì)創(chuàng)建一個(gè)先創(chuàng)建的實(shí)例對(duì)象。