單例是一種類,該類只能在第一次用的時(shí)候?qū)嵗粋€(gè)對(duì)象,后期直接調(diào)用此對(duì)象(有點(diǎn)共享的意思)。
在Foundation框架中比如NSFileManger和NSNotificationCenter,分別通過(guò)它們的類方法defaultManager和defaultCenter獲取。盡管不是嚴(yán)格意義的單例,這些類方法返回一個(gè)可以在應(yīng)用的所有代碼中訪問(wèn)到的類的共享實(shí)例。使用Objective-C實(shí)現(xiàn)單例模式的最佳方式向來(lái)有很多爭(zhēng)論,開(kāi)發(fā)者似乎每幾年就會(huì)改變他們的想法。他們也引入了一個(gè)很適合用于實(shí)現(xiàn)單例模式的函數(shù)。
該函數(shù)就是dispatch_once:
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
該函數(shù)接收一個(gè)dispatch_once用于檢查該代碼塊是否已經(jīng)被調(diào)度的謂詞(是一個(gè)長(zhǎng)整型,實(shí)際上作為BOOL使用)。它還接收一個(gè)希望在應(yīng)用的生命周期內(nèi)僅被調(diào)度一次的代碼塊,對(duì)于本例就用于shared實(shí)例的實(shí)例化。
dispatch_once不僅意味著代碼僅會(huì)被運(yùn)行一次,而且還是線程安全的,這就意味著你不需要使用諸如@synchronized之類的來(lái)防止使用多個(gè)線程或者隊(duì)列時(shí)不同步的問(wèn)題。
如果被多個(gè)線程調(diào)用,該函數(shù)會(huì)同步等等直至代碼塊完成。
實(shí)際要如何使用這些呢?
好吧,假設(shè)有一個(gè)AccountManager類,你想在整個(gè)應(yīng)用中訪問(wèn)該類的共享實(shí)例。你可以按如下代碼簡(jiǎn)單實(shí)現(xiàn)一個(gè)類方法:
+ (AccountManager *)sharedManager {
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}
這就意味著你任何時(shí)候訪問(wèn)共享實(shí)例,需要做的僅是:
AccountManager *accountManager = [AccountManager sharedManager];
就這些,你現(xiàn)在在應(yīng)用中就有一個(gè)共享的實(shí)例,該實(shí)例只會(huì)被創(chuàng)建一次。
該方法有很多優(yōu)勢(shì):
1 線程安全
2 很好滿足靜態(tài)分析器要求
3 和自動(dòng)引用計(jì)數(shù)(ARC)兼容
4 僅需要少量代碼
該方法的劣勢(shì)就是它仍然運(yùn)行創(chuàng)建一個(gè)非共享的實(shí)例:
AccountManager *accountManager = [[AccountManager alloc] init];
有些時(shí)候你希望有這種行為,但如果正在想要的是僅一個(gè)實(shí)例被實(shí)例化就需要注意這點(diǎn)。