1.單例模式的定義。
單例模式最初的定義出現於《設計模式》(艾迪生維斯理, 1994):“保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。”
使用Objective-C實現單例模式的最佳方式向來有很多爭論,開發者(包括Apple在內)似乎每幾年就會改變他們的想法。當Apple引入了Grand Central Dispatch (GCD)(Mac OS 10.6和iOS4.0),他們也引入了一個很適合用於實現單例模式的函數。
該函數就是dispatch_once:
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
該函數接收一個dispatch_once用於檢查該代碼塊是否已經被調度的謂詞(是一個長整型,實際上作爲BOOL使用)。它還接收一個希望在應用的生命週期內僅被調度一次的代碼塊,對於本例就用於shared實例的實例化。
dispatch_once不僅意味着代碼僅會被運行一次,而且還是線程安全的,這就意味着你不需要使用諸如@synchronized之類的來防止使用多個線程或者隊列時不同步的問題。
Apple的GCD Documentation證實了這一點:
如果被多個線程調用,該函數會同步等等直至代碼塊完成。
實際要如何使用這些呢?
好吧,假設有一個AccountManager類,你想在整個應用中訪問該類的共享實例。你可以按如下代碼簡單實現一個類方法:
+ (AccountManager *)sharedManager {
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate; dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}
這就意味着你任何時候訪問共享實例,需要做的僅是:
AccountManager *accountManager = [AccountManager sharedManager];
就這些,你現在在應用中就有一個共享的實例,該實例只會被創建一次。
該方法有很多優勢:
1 線程安全
2 很好滿足靜態分析器要求
3 和自動引用計數(ARC)兼容
4 僅需要少量代碼
該方法的劣勢就是它仍然運行創建一個非共享的實例:
AccountManager *accountManager = [[AccountManager alloc] init];
有些時候你希望有這種行爲,但如果正在想要的是僅一個實例被實例化就需要注意這點。
predicate
用來保證執行一次,第二個參數是要執行一次的任務block。void
_dispatch_once(
dispatch_once_t
*predicate,
dispatch_block_t
block)
{
if
(DISPATCH_EXPECT(*predicate,
~
0l
)
!= ~
0l
)
{
dispatch_once(predicate,
block);
}
}
#define
dispatch_once _dispatch_once
展開DISPATCH_EXPECT, 是__builtin_expect((x), (v)) ,__builtin_expect是GCC(version>=2.9)引進的宏,其作用就是幫助編譯器判斷條件跳轉的預期值,避免跳轉造成時間浪費,並沒有改變其對真值的判斷。