dispatch_once概念解析
dispatch_once
是 Grand Central Dispatch(GCD)
中的一種線程安全的單例創(chuàng)建方式乏盐,在 iOS 開發(fā)中常被用來創(chuàng)建全局唯一的單例對(duì)象。其核心是利用 dispatch_once 函數(shù)神凑,確保指定 block 只會(huì)被執(zhí)行一次法竞,并且是線程安全的强挫,也就是說不會(huì)存在多個(gè)線程同時(shí)執(zhí)行該 block 的情況俯渤。
dispatch_once
函數(shù)的聲明如下:
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
它包含了一個(gè) predicate 參數(shù)和一個(gè) block 參數(shù)型宝。其中,predicate 是一個(gè)指向 dispatch_once_t 結(jié)構(gòu)體的指針梨树,用來判斷該 block 是否已經(jīng)被執(zhí)行過岖寞。block 則是需要執(zhí)行的單例創(chuàng)建操作。
通常情況下指巡,我們會(huì)在 dispatch_once 函數(shù)中執(zhí)行以下兩個(gè)步驟:
- 調(diào)用 dispatch_once 函數(shù)時(shí)隶垮,dispatch_once_t 結(jié)構(gòu)體會(huì)被初始化為 0。
- 在 block 中執(zhí)行單例創(chuàng)建操作勉耀,創(chuàng)建成功后將 dispatch_once_t 結(jié)構(gòu)體的值修改為非 0 值蹋偏。
完成上述兩個(gè)步驟后,再次調(diào)用 dispatch_once 函數(shù)時(shí)椭住,由于 dispatch_once_t 的值已經(jīng)被修改為非 0 值字逗,dispatch_once 函數(shù)將不會(huì)再次執(zhí)行 block 中的內(nèi)容宅广,從而確保該單例只會(huì)被創(chuàng)建一次。
整個(gè)程序運(yùn)行中只會(huì)執(zhí)行一次俭厚,使用dispatch_once可以簡(jiǎn)化代碼并且徹底保證線程安全驶臊,開發(fā)者根本無須擔(dān)心加鎖或者同步叼丑。所有問題都由GCD在底層處理扛门。由于每次調(diào)用時(shí)都必須使用完全相同的標(biāo)記,所以標(biāo)記要聲明成static星立。所以用在單例模式上是最好的
下面是一個(gè)使用 dispatch_once 函數(shù)創(chuàng)建單例的例子:
+ (instancetype)sharedInstance {
static MySingleton *instance;
static dispatch_once_t dispatchOnceToken;
dispatch_once(&dispatchOnceToken, ^{
instance = [[MySingleton alloc] init];
});
return instance;
}
此代碼中绰垂,dispatch_once_t 結(jié)構(gòu)體的值將在整個(gè)應(yīng)用程序生命周期內(nèi)只初始化一次火焰。另外,使用 GCD 的單例創(chuàng)建方式昌简,可以減少線程沖突,提高代碼的性能和可讀性纺酸。
使用場(chǎng)景
dispatch_once一般使用在單例模式上,其要點(diǎn)是整個(gè)程序運(yùn)行中只會(huì)執(zhí)行一次餐蔬。當(dāng)然只要是那些只需要執(zhí)行一次的方法佑附,用dispatch_once最簡(jiǎn)單最安全。