單例模式的作用
可以保證在程序運(yùn)行過(guò)程,一個(gè)類(lèi)只有一個(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 = [super allocWithZone:zone];
}
}
}
return _instance;
}
提供1個(gè)類(lèi)方法讓外界訪問(wèn)唯一的實(shí)例
(instancetype)sharedMusicTool {
if (_instance == nil) { //
防止頻繁加鎖
@synchronized(self) {
if
(_instance== nil) { //
防止創(chuàng)建多次
_instance
= [[self alloc]
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 {return 1; }
(oneway void)release {}
- (id)autorelease { return
self; }
************************筆記****************************
1.單例模式
- 1.1 概念相關(guān)
(1)單例模式
在程序運(yùn)行過(guò)程,一個(gè)類(lèi)只有一個(gè)實(shí)例
(2)使用場(chǎng)合
在整個(gè)應(yīng)用程序中,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)
- 1.2
ARC實(shí)現(xiàn)單例
(1)步驟
01 在類(lèi)的內(nèi)部提供一個(gè)static修飾的全局變量
02 提供一個(gè)類(lèi)方法,方便外界訪問(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í)例
static XMGTools *_instance;
類(lèi)方法,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
注意:這里建議使用self,而不是直接使用類(lèi)名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;
}
mutableCopy 創(chuàng)建一個(gè)新的可變對(duì)象,并初始化為原對(duì)象的值,新對(duì)象的引用計(jì)數(shù)為1;
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 在類(lèi)的內(nèi)部提供一個(gè)static修飾的全局變量
02 提供一個(gè)類(lèi)方法,方便外界訪問(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í)例
static XMGTools *_instance;
類(lèi)方法,返回一個(gè)單例對(duì)象
+(instancetype)shareTools
{
注意:這里建議使用self,而不是直接使用類(lèi)名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)行過(guò)程中都擁有且只有一份,程序退出之后被釋放,所以不需要對(duì)引用計(jì)數(shù)器操作
-(oneway void)release
{
}
-(instancetype)retain
{
return _instance;
}
慣用法,有經(jīng)驗(yàn)的程序員通過(guò)打印retainCount這個(gè)值可以猜到這是一個(gè)單例
-(NSUInteger)retainCount
{
return MAXFLOAT;
}
- 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