單例模式的作用
可以保證在程序運(yùn)行過(guò)程足陨,一個(gè)類只有一個(gè)實(shí)例琴拧,而且該實(shí)例易于供外界訪問(wèn)
從而方便地控制了實(shí)例個(gè)數(shù)蝌借,并節(jié)約系統(tǒng)資源?
單例模式的使用場(chǎng)合
在整個(gè)應(yīng)用程序中,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)?
單例模式在ARC\MRC環(huán)境下的寫(xiě)法有所不同吟吝,需要編寫(xiě)2套不同的代碼
可以用宏判斷是否為ARC環(huán)境
#if __has_feature(objc_arc)
// ARC
#else
// MRC
#endif
單例模式- ARC
ARC中菱父,單例模式的實(shí)現(xiàn)
在.m中保留一個(gè)全局的static的實(shí)例
static id_instance;
重寫(xiě)allocWithZone:方法,在這里創(chuàng)建唯一的實(shí)例(注意線程安全)
+ (id)allocWithZone:(struct_NSZone*)zone {
???if(_instance==nil) {?防止頻繁加鎖
???????@synchronized(self) {
???????????if(_instance==nil) {?防止創(chuàng)建多次
? _instance= [superallocWithZone:zone];
??????????? }
??????? }
??? }
???return_instance;
}?
提供1個(gè)類方法讓外界訪問(wèn)唯一的實(shí)例
+ (instancetype)sharedMusicTool {
???if(_instance==nil) {防止頻繁加鎖
???????@synchronized(self) {
???????????if(_instance==nil) {?防止創(chuàng)建多次
??????????????_instance= [[selfalloc]init];
??????????? }
??????? }
??? }
???return_instance;
}
實(shí)現(xiàn)copyWithZone:方法
- (id)copyWithZone:(struct_NSZone*)zone {
???return_instance;
}
單例模式–非ARC
非ARC中(MRC)爸黄,單例模式的實(shí)現(xiàn)(比ARC多了幾個(gè)步驟)
實(shí)現(xiàn)內(nèi)存管理方法
- (id)retain {return self; }
- (NSUInteger)retainCount {return1; }
- (oneway void)release {}
- (id)autorelease {return self; }
1.單例模式
- 1.1概念相關(guān)
(1)單例模式
在程序運(yùn)行過(guò)程滞伟,一個(gè)類只有一個(gè)實(shí)例
(2)使用場(chǎng)合
在整個(gè)應(yīng)用程序中,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)
- 1.2 ARC實(shí)現(xiàn)單例
(1)步驟
01在類的內(nèi)部提供一個(gè)static修飾的全局變量
02提供一個(gè)類方法炕贵,方便外界訪問(wèn)
03重寫(xiě)+allocWithZone方法梆奈,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04嚴(yán)謹(jǐn)起見(jiàn),重寫(xiě)-copyWithZone方法和-MutableCopyWithZone方法
(2)相關(guān)代碼
提供一個(gè)static修飾的全局變量称开,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
staticXMGTools *_instance;
類方法亩钟,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
???注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)
? ?return[[selfalloc]init];
}
保證永遠(yuǎn)只分配一次存儲(chǔ)空間
+(instancetype)allocWithZone:(struct_NSZone *)zone
{
???使用GCD中的一次性代碼
???static dispatch_once_t onceToken;
???dispatch_once(&onceToken, ^{
???_instance = [super allocWithZone:zone];
?????? });
???使用加鎖的方式,保證只分配一次存儲(chǔ)空間
???@synchronized(self) {
???????if(_instance ==nil) {
??????????? _instance = [superallocWithZone:zone];
??????? }
??? }
???return_instance;
}
?1. mutableCopy創(chuàng)建一個(gè)新的可變對(duì)象鳖轰,并初始化為原對(duì)象的值清酥,新對(duì)象的引用計(jì)數(shù)為1;
?2. copy返回一個(gè)不可變對(duì)象蕴侣。分兩種情況:(1)若原對(duì)象是不可變對(duì)象焰轻,那么返回原對(duì)象,并將其引用計(jì)數(shù)加1昆雀;(2)若原對(duì)象是可變對(duì)象辱志,那么創(chuàng)建一個(gè)新的不可變對(duì)象,并初始化為原對(duì)象的值狞膘,新對(duì)象的引用計(jì)數(shù)為1揩懒。
讓代碼更加的嚴(yán)謹(jǐn)
-(nonnull id)copyWithZone:(nullableNSZone *)zone
{
??? return [[self class] allocWithZone:zone];
???return_instance;
}
-(nonnull id)mutableCopyWithZone:(nullableNSZone *)zone
{
???return_instance;
}
- 1.3 MRC實(shí)現(xiàn)單例
(1)實(shí)現(xiàn)步驟
01在類的內(nèi)部提供一個(gè)static修飾的全局變量
02提供一個(gè)類方法,方便外界訪問(wèn)
03重寫(xiě)+allocWithZone方法挽封,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04嚴(yán)謹(jǐn)起見(jiàn)已球,重寫(xiě)-copyWithZone方法和-MutableCopyWithZone方法
05重寫(xiě)release方法
06重寫(xiě)retain方法
07建議在retainCount方法中返回一個(gè)最大值
(2)配置MRC環(huán)境知識(shí)
01注意ARC不是垃圾回收機(jī)制,是編譯器特性
02配置MRC環(huán)境:build setting ->搜索automatic ref->修改為NO
(3)相關(guān)代碼
提供一個(gè)static修飾的全局變量辅愿,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
staticXMGTools *_instance;
類方法智亮,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
???注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)
???return[[selfalloc]init];
}
保證永遠(yuǎn)只分配一次存儲(chǔ)空間
+(instancetype)allocWithZone:(struct_NSZone *)zone
{
???使用GCD中的一次性代碼
?????? static dispatch_once_t onceToken;
?????? dispatch_once(&onceToken, ^{
?????? _instance = [super allocWithZone:zone];
?????? });
???使用加鎖的方式,保證只分配一次存儲(chǔ)空間
???@synchronized(self) {
???????if(_instance ==nil) {
??????????? _instance = [superallocWithZone:zone];
??????? }
??? }
?? return_instance;
}
讓代碼更加的嚴(yán)謹(jǐn)
-(nonnull id)copyWithZone:(nullableNSZone *)zone
{
?? return [[self class] allocWithZone:zone];
???return_instance;
}
-(nonnull id)mutableCopyWithZone:(nullableNSZone *)zone
{
???return_instance;
}
在MRC環(huán)境下点待,如果用戶retain了一次鸽素,那么直接返回instance變量,不對(duì)引用計(jì)數(shù)器+1
如果用戶release了一次亦鳞,那么什么都不做,因?yàn)閱卫J皆谡麄€(gè)程序運(yùn)行過(guò)程中都擁有且只有一份,程序退出之后被釋放燕差,所以不需要對(duì)引用計(jì)數(shù)器操作
-(oneway void)release
{
}
-(instancetype)retain
{
???return_instance;
}
慣用法遭笋,有經(jīng)驗(yàn)的程序員通過(guò)打印retainCount這個(gè)值可以猜到這是一個(gè)單例
-(NSUInteger)retainCount
{
???returnMAXFLOAT;
}
- 1.4通用版本
(1)有意思的對(duì)話
01問(wèn):寫(xiě)一份單例代碼在ARC和MRC環(huán)境下都適用?
答:可以使用條件編譯來(lái)判斷當(dāng)前項(xiàng)目環(huán)境是ARC還是MRC
02問(wèn):條件編譯的代碼呢徒探,么么噠瓦呼?
答:條件編譯
#if __has_feature(objc_arc)
如果是ARC,那么就執(zhí)行這里的代碼1
#else
如果不是ARC测暗,那么就執(zhí)行代理的代碼2
#endif
03問(wèn):在項(xiàng)目里面往往需要實(shí)現(xiàn)很多的單例央串,比如下載、網(wǎng)絡(luò)請(qǐng)求碗啄、音樂(lè)播放等等质和,弱弱的問(wèn)一句單例可以用繼承嗎?
答:?jiǎn)卫遣豢梢杂美^承的稚字,如果想寫(xiě)一次四處使用饲宿,那么推薦親使用帶參數(shù)的宏定義啦!
04問(wèn):宏定義怎么弄胆描?
答:這個(gè)嘛~~回頭看一眼我的代碼咯瘫想,親。
(2)使用帶參數(shù)的宏完成通用版單例模式代碼
01注意條件編譯的代碼不能包含在宏定義里面
02宏定義的代碼只需要寫(xiě)一次就好昌讲,之后直接拖到項(xiàng)目中用就OK