單例
一般來說,在iOS的工程中馆纳, 通用的tool一般都會(huì)設(shè)計(jì)成單例,這樣能保證在程序運(yùn)行過程中复亏,程序中只有一個(gè)單例對象垃你,方便數(shù)據(jù)的傳輸和處理椅文。
如果為了擴(kuò)展此單例類,希望在此基礎(chǔ)上增加面向各模塊專用的單例方法惜颇,該如何處理呢皆刺。
可以采用的方法有兩種:
- 分類:可以針對各個(gè)模塊創(chuàng)建對應(yīng)的分類,并添加方法凌摄。缺點(diǎn)是不能繼承原有單例的屬性羡蛾。
- 繼承:也可以針對各個(gè)模塊創(chuàng)建出對應(yīng)的子類,并添加方法锨亏。也可以繼承父類的屬性痴怨。
繼承單例遇到的問題
因?yàn)閱卫龑ο笤诔绦蛑兄粫?huì)創(chuàng)建一次,創(chuàng)建成功后再次訪問單例對象器予,訪問的是同一個(gè)對象浪藻,故子類如果采用父類的方法進(jìn)行創(chuàng)建的話,訪問的對象還是父類乾翔,子類添加的屬性和方法將會(huì)無法訪問而造成crash爱葵。
// 父類
QYSingleton *singleton = [QYSingleton shareSingleton];
NSLog(@"%@ - %p", singleton, singleton);
// 方法
[singleton run];
打印結(jié)果
單例繼承[3651:162046] name: father, age: 30, sex: male - 0x604000221da0
單例繼承[3711:165295] QYSingleton run
// 子類
// 子類:采用繼承的父類的類方法進(jìn)行創(chuàng)建
QYSubSingleton *subSingleton = [QYSubSingleton shareSingleton];
NSLog(@"%@ - %p", subSingleton, subSingleton);
打印結(jié)果
name: father, age: 30, sex: male - 0x604000221da0
由以上結(jié)果可知,這兩個(gè)對象的地址是一樣的,也證明了程序中只會(huì)創(chuàng)建一份單例對象萌丈。
- 給子類對象添加屬性暇韧,因創(chuàng)建出來的對象為父類對象,故
-[QYSingleton setHobby:]: unrecognized selector sent to instance 0x60400002b8a0
找不到屬性對應(yīng)的setter
而crash
. - 給子類對象添加方法浓瞪,同樣的會(huì)
-[QYSingleton walk]: unrecognized selector sent to instance 0x6000002212e0
子類的創(chuàng)建方法
- 通過
alloc
懈玻、init
進(jìn)行創(chuàng)建
// 父類
QYSingleton *singleton = [QYSingleton shareSingleton];
NSLog(@"%@ - %p", singleton, singleton);
// 方法
[singleton run];
// 打印結(jié)果
單例繼承[6181:308541] name: father, age: 30, sex: male - 0x6040000349e0
單例繼承[6220:310333] QYSingleton run
// 通過alloc、init進(jìn)行創(chuàng)建
QYSubSingleton *subSingleton = [[QYSubSingleton alloc] init];
// 繼承的屬性
subSingleton.name = @"subObject";
// 子類添加的屬性
subSingleton.hobby = @"游泳";
NSLog(@"%@ - %p", subSingleton, subSingleton);
// 繼承的方法
[subSingleton run];
// 添加的方法
[subSingleton walk];
// 打印的結(jié)果
單例繼承[6220:310333] name: subObject, age: 30, sex: male, hobby:游泳 - 0x60000025ad90
// 調(diào)用父類的方法
單例繼承[6220:310333] QYSubSingleton run
// 子類添加的方法
單例繼承[6220:310333] QYSubSingleton walk
由打印可知乾颁,這樣才能創(chuàng)建出新的子類對象涂乌,并且可以更改父類的初始屬性,添加新的屬性和方法
- 給子類添加單例的方法進(jìn)行創(chuàng)建
- 方法:
+ (instancetype)shareSubSingle;
- 使用:
QYSubSingleton *subSingleton = [QYSubSingleton shareSubSingle];
- 驗(yàn)證:將
alloc英岭、init
替換為shareSubSingle
創(chuàng)建子類對象進(jìn)行驗(yàn)證 - 結(jié)論:經(jīng)驗(yàn)證湾盒,這樣也能創(chuàng)建出新的子類對象,并能添加屬性和方法
更嚴(yán)謹(jǐn)?shù)膭?chuàng)建單例的方式
以上創(chuàng)建單例和單例的子類都不是很嚴(yán)謹(jǐn)诅妹,父類通過shareSingleton
創(chuàng)建的對象罚勾,和通過alloc、init
創(chuàng)建的對象是不一樣的吭狡。
這是因?yàn)榧庋辏琌C通過allocWithZone:這個(gè)方法來申請內(nèi)存的,故我們要覆寫這個(gè)方法划煮,保證創(chuàng)建出來的對象是唯一的送丰。
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [QYSingleton shareSingleton];
}
修改shareSingleton
為:
+ (instancetype)shareSingleton {
static dispatch_once_t onceToken;
static QYSingleton *singleton = nil;
dispatch_once(&onceToken, ^{
singleton = [[super allocWithZone:NULL] init];
});
return singleton;
}
這樣就不管是使用什么方法,創(chuàng)建出來的對象就都是唯一的了弛秋。
創(chuàng)建繼承的單例
因?yàn)閱卫哂形ㄒ恍云黪铮WC每個(gè)創(chuàng)建的類是不同的,所以在每個(gè)類生成時(shí)蟹略,我們動(dòng)態(tài)的給類綁定唯一的對象登失。
使用runTime的關(guān)聯(lián)對象進(jìn)行創(chuàng)建。
如下:
/** 單例對象 */
+ (instancetype)shareObject {
// 獲取當(dāng)前對象的類
Class selfClass = [self class];
// 從類中獲取對象
id instance = objc_getAssociatedObject(selfClass, @"shareObject");
if (!instance) {
// 不存在挖炬,創(chuàng)建對象
instance = [[super allocWithZone:NULL] init];
// 給類綁定對象
objc_setAssociatedObject(selfClass, @"shareObject", instance, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return instance;
}
/** 保證alloc揽浙、init也創(chuàng)建同樣的對象 */
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
// 獲取當(dāng)前對象的類
Class class = [self class];
// 返回當(dāng)前類綁定的對象
return [class shareObject];
}
驗(yàn)證:
QYObject *objc = [QYObject shareObject];
NSLog(@"%p", objc);
QYObject *objc2 = [[QYObject alloc] init];
NSLog(@"%p", objc2);
QYSubObject *subObjc = [QYSubObject shareObject];
NSLog(@"%p", subObjc);
QYSubObject *subObjc2 = [[QYSubObject alloc] init];
NSLog(@"%p", subObjc2);
結(jié)果:
2018-09-12 09:43:22.764627+0800 單例繼承[1639:49824] 0x6040000030d0
2018-09-12 09:43:22.764815+0800 單例繼承[1639:49824] 0x6040000030d0
2018-09-12 09:43:22.764953+0800 單例繼承[1639:49824] 0x604000002d90
2018-09-12 09:43:22.765140+0800 單例繼承[1639:49824] 0x604000002d90