淺析單例設計模式

在開發(fā)中經(jīng)常會用到單例設計模式啸罢,目的就是為了在程序的整個生命周期內(nèi)押袍,只會創(chuàng)建一個類的實例對象甸饱,而且只要程序不被殺死联四,該實例對象就不會被釋放撑碴。保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

創(chuàng)建單例的幾種方式

方式一

傳統(tǒng)且正規(guī)的方法是把一次性代碼dispatch_once寫到allocWithZone:方法中去朝墩,目的是保證allocWithZone:方法只被調(diào)用一次醉拓,這樣一來,凡是通過[[class alloc] init]方法創(chuàng)建的實例收苏,都是指向同一個對象廉嚼。代碼如下:

+ (instancetype)shareInstance
{
   ALYNetworkManager *instance = [[self alloc] init];
   return instance;
}

static ALYNetworkManager *_instance = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
       _instance = [super allocWithZone:zone];
   });
   return _instance;
}

-(id)copyWithZone:(NSZone *)zone
{
   // 需要遵守NSCopying協(xié)議
   return _instance;
}

方式二

更加簡單的方式是把一次性代碼dispatch_once寫到獲取單例對象的類方法中去。保證只要通過這個類方法獲取的對象都是同一個實例倒戏。但是因為沒有重寫allocWithZone:方法怠噪,所以如果有開發(fā)者在外部直接調(diào)用[[class alloc] init]方法獲取實例,那么獲取的實例和通過類方法獲取的實例就不是同一個實例杜跷。這樣就不能保證實例的全局唯一性傍念。所以矫夷,尤其在多人開發(fā)中,采用這種方式存在一定的風險性憋槐。代碼如下:

+ (ALYNetworkManager *)sharedInstance {
    static ALYNetworkManager *instance;
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        instance = [[ALYNetworkManager alloc]init];
    });
    return instance;
}

如下圖双藕,可以看到,通過shareInstance類方法獲取的實例始終是同一個阳仔,而通過[[class alloc] init] 和 shareInstance類方法獲取的實例并不是同一個:


方式三

另外忧陪,除了使用一次性代碼dispatch_once保證多線程情況下獲取的仍然是同一個對象,我們還可以使用同步鎖的方式達到這個目的近范,代碼如下:

+ (instancetype)shareInstance {
    static ALYNetworkManager *instance = nil;
    instance = [[ALYNetworkManager alloc] init];
   
    return instance;
}

static ALYNetworkManager *_instance = nil;
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    @synchronized (self) {
        if (!_instance) {
            _instance = [super allocWithZone:zone];
        }
    }
    return _instance;
}

驗證多線程下獲取的是否為同一個實例嘶摊,如下圖:


方式四

當然還可以在單例的全局訪問點(類方法)中使用同步鎖,其結果和方式二是一樣的:外部都不能直接通過調(diào)用[[class alloc] init]方法來獲取單例评矩,代碼如下:

+ (instancetype)shareInstance {
    static ALYNetworkManager *instance = nil;
    @synchronized (self) {
        if (!instance) {
            instance = [[ALYNetworkManager alloc] init];
        }
    }
    return instance;
}

單例工具類的創(chuàng)建

此處以利用dispatch_once一次性代碼 + 宏定義的方式抽取出一個通用的單例宏叶堆,其實在網(wǎng)上隨便一搜,就可以搜到一大把單例宏斥杜。

ARC\MRC判斷

#if __has_feature(objc_arc)

#else

#endif

宏抽取

#define interfaceSingleton(name)  +(instancetype)share##name


#if __has_feature(objc_arc)
// ARC
#define implementationSingleton(name)  \
+ (instancetype)share##name \
{ \
name *instance = [[self alloc] init]; \
return instance; \
} \
static name *_instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[super allocWithZone:zone] init]; \
}); \
return _instance; \
} \
- (id)copyWithZone:(NSZone *)zone{ \
return _instance; \
} \
- (id)mutableCopyWithZone:(NSZone *)zone \
{ \
return _instance; \
}
#else
// MRC

#define implementationSingleton(name)  \
+ (instancetype)share##name \
{ \
name *instance = [[self alloc] init]; \
return instance; \
} \
static name *_instance = nil; \
+ (instancetype)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instance = [[super allocWithZone:zone] init]; \
}); \
return _instance; \
} \
- (id)copyWithZone:(NSZone *)zone{ \
return _instance; \
} \
- (id)mutableCopyWithZone:(NSZone *)zone \
{ \
return _instance; \
} \
- (oneway void)release \
{ \
} \
- (instancetype)retain \
{ \
return _instance; \
} \
- (NSUInteger)retainCount \
{ \
return  MAXFLOAT; \
}
#endif

以后如果需要創(chuàng)建單例工具類直接創(chuàng)建一個Singleton.h文件,把上面的代碼拷貝到.h文件中虱颗。在單例類(拿Person類為例)中導入這個頭文件。直接在單例類的.h文件中interfaceSingleton(name)傳入?yún)?shù)蔗喂,.m文件中implementationSingleton(name)傳入?yún)?shù)即可忘渔。

如下:

/************ALYNetworkManager.h**********/
#import <Foundation/Foundation.h>
#import "Singleton.h"

@interface ALYNetworkManager : NSObject

interfaceSingleton(ALYNetworkManager);

@end

/************ALYNetworkManager.m**********/
#import "ALYNetworkManager.h"

@implementation ALYNetworkManager


implementationSingleton(ALYNetworkManager)

@end

git地址點這里

文/VV木公子(簡書作者)
PS:如非特別說明,所有文章均為原創(chuàng)作品缰儿,著作權歸作者所有辨萍,轉(zhuǎn)載請聯(lián)系作者獲得授權,并注明出處返弹,所有打賞均歸本人所有锈玉!

如果您是iOS開發(fā)者,或者對本篇文章感興趣义起,請關注本人拉背,后續(xù)會更新更多相關文章!敬請期待默终!

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末椅棺,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子齐蔽,更是在濱河造成了極大的恐慌两疚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件含滴,死亡現(xiàn)場離奇詭異诱渤,居然都是意外死亡,警方通過查閱死者的電腦和手機谈况,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門勺美,熙熙樓的掌柜王于貴愁眉苦臉地迎上來递胧,“玉大人,你說我怎么就攤上這事赡茸《衅ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵占卧,是天一觀的道長遗菠。 經(jīng)常有香客問我,道長华蜒,這世上最難降的妖魔是什么辙纬? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮友多,結果婚禮上,老公的妹妹穿的比我還像新娘堤框。我一直安慰自己域滥,他們只是感情好,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布蜈抓。 她就那樣靜靜地躺著启绰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沟使。 梳的紋絲不亂的頭發(fā)上委可,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音腊嗡,去河邊找鬼着倾。 笑死,一個胖子當著我的面吹牛燕少,可吹牛的內(nèi)容都是我干的卡者。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼客们,長吁一口氣:“原來是場噩夢啊……” “哼崇决!你這毒婦竟也來了?” 一聲冷哼從身側響起底挫,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤恒傻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后建邓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盈厘,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年官边,在試婚紗的時候發(fā)現(xiàn)自己被綠了扑庞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片譬重。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖罐氨,靈堂內(nèi)的尸體忽然破棺而出臀规,到底是詐尸還是另有隱情,我是刑警寧澤栅隐,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布塔嬉,位于F島的核電站,受9級特大地震影響租悄,放射性物質(zhì)發(fā)生泄漏谨究。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一泣棋、第九天 我趴在偏房一處隱蔽的房頂上張望胶哲。 院中可真熱鬧,春花似錦潭辈、人聲如沸鸯屿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寄摆。三九已至,卻和暖如春修赞,著一層夾襖步出監(jiān)牢的瞬間婶恼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工柏副, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留勾邦,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓割择,卻偏偏與公主長得像检痰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锨推,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容