- 1.1 概念
(1)單例模式
(1.1)在程序運(yùn)行過程,一個(gè)類只有一個(gè)實(shí)例伍纫,而且該實(shí)例易于供外界訪問
(1.2)方便地控制了實(shí)例個(gè)數(shù)莹规,并節(jié)約系統(tǒng)資源
(1.3)單例是不可以用繼承的,因?yàn)椴荒芨割惻c子類共用一個(gè)全局變量
(2)使用場合
在整個(gè)應(yīng)用程序中舞虱,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)母市;
可以理解為當(dāng)需要一個(gè)24小時(shí)響應(yīng)的“馬仔”幫你實(shí)現(xiàn)某些功能時(shí),使用單例焕刮。
(3)約束-不要濫用單例模式
1. 單例是一種全局狀態(tài)配并,意味著App的任何地方都可以和這個(gè)單例進(jìn)行交互高镐,無形中增加了代碼的耦合
2. 單例的生命周期難以控制,雖然可以在單例中提供方法設(shè)為nil進(jìn)行釋放观腊。
- 1.2 實(shí)現(xiàn)單例(在ARC與MRC中均可執(zhí)行)
(1)實(shí)現(xiàn)步驟
01 在類的內(nèi)部提供一個(gè)static修飾的全局變量
02 重寫+allocWithZone方法算行,保證永遠(yuǎn)都只為單例對(duì)象分配一次內(nèi)存空間
03 提供一個(gè)類方法,方便外界訪問
04 嚴(yán)謹(jǐn)起見州邢,重寫-copyWithZone方法和-MutableCopyWithZone方法
05 通過條件編譯判斷是否是ARC{__has_feature(objc_arc)}儡陨,若是,則不再執(zhí)行代碼量淌,否則執(zhí)行下述06-09代碼
06 重寫release方法
07 重寫retain方法
08 建議在retainCount方法中返回一個(gè)最大值
09 結(jié)束條件編譯
(2)如果在MRC中運(yùn)行骗村,需配置MRC環(huán)境知識(shí)
01 注意ARC不是垃圾回收機(jī)制,是編譯器特性
02 配置MRC環(huán)境:build setting ->搜索automatic ref->修改為NO
(3)相關(guān)代碼
- allocWithZone方法中加鎖或GCD一次性代碼詳見多線程
//提供一個(gè)static修飾的全局變量呀枢,強(qiáng)引用著已經(jīng)實(shí)例化的單例對(duì)象實(shí)例 static id _instance; //保證永遠(yuǎn)只分配一次存儲(chǔ)空間 +(instancetype)allocWithZone:(struct _NSZone *)zone { //使用GCD中的一次性代碼 // static dispatch_once_t onceToken; // dispatch_once(&onceToken, ^{ // _instance = [[super allocWithZone:zone]init]; // }); //使用加鎖的方式胚股,保證只分配一次存儲(chǔ)空間 @synchronized(self) { if (_instance == nil) { _instance = [super allocWithZone:zone]; } } return _instance; } //類方法,返回一個(gè)單例對(duì)象 +(instancetype)shareTools { //注意:這里建議使用self,而不是直接使用類名Tools(考慮繼承) return [[self alloc]init]; } //讓代碼更加的嚴(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; } #if __has_feature(objc_arc) //如果是ARC環(huán)境下 #else //如果是MRC環(huán)境下 //在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; } #endif
單例封裝宏
01 注意條件編譯的代碼不能包含在宏定義里面
02 宏定義的代碼只需要寫一次就好,之后直接拖到項(xiàng)目中用就OK
- .h文件
#define SingleH(name) +(instancetype)share##name;
- .m文件
#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