1.單例模式
- 1.1 概念相關(guān)
(1)單例模式
在程序運(yùn)行過程朴上,一個(gè)類只有一個(gè)實(shí)例
(2)使用場(chǎng)合
在整個(gè)應(yīng)用程序中萌踱,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)
- 1.2 ARC實(shí)現(xiàn)單例
(1)步驟(重點(diǎn))
01 在類的內(nèi)部提供一個(gè)static修飾的全局變量//通過該變量保證只生成一個(gè)對(duì)象(還需要加一把鎖,防止多線程并發(fā)的情況)
02 提供一個(gè)類方法暖眼,方便外界訪問
03 重寫+allocWithZone方法,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04 嚴(yán)謹(jǐn)起見阅酪,重寫-copyWithZone方法和-MutableCopyWithZone方法
(2)相關(guān)代碼(重點(diǎn))
//提供一個(gè)static修飾的全局變量,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例
static XMGTools *_instance;
//類方法级野,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
//注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)
return [[self alloc]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 = [super allocWithZone: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:(nullable NSZone *)zone
{
// return [[self class] allocWithZone:zone];
return _instance;
}
-(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
}
- 1.3 MRC實(shí)現(xiàn)單例
(1)實(shí)現(xiàn)步驟
01 在類的內(nèi)部提供一個(gè)static修飾的全局變量
02 提供一個(gè)類方法策吠,方便外界訪問
03 重寫+allocWithZone方法逛裤,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
04 嚴(yán)謹(jǐn)起見,重寫-copyWithZone方法和-MutableCopyWithZone方法
05 重寫release方法(不需要被釋放,所以不需要做什么)
06 重寫retain方法
07 建議在retainCount方法中返回一個(gè)最大值(讓其他程序員明白這是一個(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í)例
static XMGTools *_instance;
//類方法,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
//注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承)
return [[self alloc]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 = [super allocWithZone:zone];
}
}
return _instance;
}
//讓代碼更加的嚴(yán)謹(jǐn)
-(nonnull id)copyWithZone:(nullable NSZone *)zone
{
// return [[self class] allocWithZone:zone];
return _instance;
}
-(nonnull id)mutableCopyWithZone:(nullable NSZone *)zone
{
return _instance;
}
//在MRC環(huán)境下蝙砌,如果用戶retain了一次,那么直接返回instance變量跋理,不對(duì)引用計(jì)數(shù)器+1
//如果用戶release了一次择克,那么什么都不做,因?yàn)閱卫J皆谡麄€(gè)程序運(yùn)行過程中都擁有且只有一份前普,程序退出之后被釋放肚邢,所以不需要對(duì)引用計(jì)數(shù)器操作
-(oneway void)release
{
}
-(instancetype)retain
{
return _instance;
}
//慣用法,有經(jīng)驗(yàn)的程序員通過打印retainCount這個(gè)值可以猜到這是一個(gè)單例
-(NSUInteger)retainCount
{
return MAXFLOAT;
}
- 1.4 通用版本
(1)有意思的對(duì)話
01 問:寫一份單例代碼在ARC和MRC環(huán)境下都適用拭卿?
答:可以使用條件編譯來判斷當(dāng)前項(xiàng)目環(huán)境是ARC還是MRC
02 問:條件編譯的代碼呢道偷,么么噠?
//答:條件編譯
#if __has_feature(objc_arc)
//如果是ARC记劈,那么就執(zhí)行這里的代碼1
#else
//如果不是ARC勺鸦,那么就執(zhí)行代理的代碼2
#endif
03 問:在項(xiàng)目里面往往需要實(shí)現(xiàn)很多的單例,比如下載目木、網(wǎng)絡(luò)請(qǐng)求换途、音樂播放等等,弱弱的問一句單例可以用繼承嗎刽射?
答:?jiǎn)卫遣豢梢杂美^承的军拟,如果想一次寫就,四處使用誓禁,那么推薦親使用帶參數(shù)的宏定義啦懈息!
04 問:宏定義怎么弄?
答:這個(gè)嘛~~回頭看一眼我的代碼咯摹恰,親辫继。
(2)使用帶參數(shù)的宏完成通用版單例模式代碼
01 注意條件編譯的代碼不能包含在宏定義里面
02 宏定義的代碼只需要寫一次就好,之后直接拖到項(xiàng)目中用就OK
- Posted by 博客園·文頂頂
- revise by 簡(jiǎn)書.lovepeijun