2012-02-02 19 views
295

在ARC下的單例的共享實例訪問器中使用dispatch_once的確切原因是什麼?爲什麼Apple建議使用dispatch_once來實現ARC下的單例模式?

+ (MyClass *)sharedInstance 
{ 
    // Static local predicate must be initialized to 0 
    static MyClass *sharedInstance = nil; 
    static dispatch_once_t onceToken = 0; 
    dispatch_once(&onceToken, ^{ 
     sharedInstance = [[MyClass alloc] init]; 
     // Do any other initialisation stuff here 
    }); 
    return sharedInstance; 
} 

是不是一個壞主意,在後臺異步實例單身?我的意思是,如果我請求共享實例並立即依賴它,會發生什麼情況,但dispatch_once需要等到聖誕節才創建我的對象?它不立即返回正確?至少這似乎是Grand Central Dispatch的重點。

那他們爲什麼要這樣做呢?

+0

'注:靜態和全局變量默認爲零。' – ikkentim 2016-09-13 09:56:32

回答

406

dispatch_once()是絕對同步的。並非所有的GCD方法都是異步執行的(例如,dispatch_sync()是同步的)。採用dispatch_once()替換下列成語:

+ (MyClass *)sharedInstance { 
    static MyClass *sharedInstance; 
    @synchronized(self) { 
     if (sharedInstance == nil) { 
      sharedInstance = [[MyClass alloc] init]; 
     } 
    } 
    return sharedInstance; 
} 

dispatch_once()在這個的好處是,它的速度更快。它在語義上也更清潔,因爲它還可以保護您免受多個線程的影響,執行sharedInstance的alloc init - 如果它們都在同一時間嘗試。它不會允許創建兩個實例。 dispatch_once()的整個想法是「只做一次,只做一次」,這正是我們正在做的。

+4

爲了論證的緣故,我需要注意[文檔](https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/ func/dispatch_once)並沒有說它正在被同步執行。它只是說多個同時調用將被序列化。 – expert 2013-08-25 21:28:49

+5

你聲稱速度更快 - 速度要快多少?我沒有理由認爲你不說實話,但我希望看到一個簡單的基準。 – 2013-10-01 18:30:24

+29

我只是做了一個簡單的基準測試(在iPhone 5上),看起來像dispatch_once比@synchronized快大約2倍。 – 2013-10-01 18:44:00

39

因爲它只會運行一次。所以如果你嘗試從不同的線程訪問它兩次,它不會導致問題。

Mike Ash在他的博客文章中有Care and Feeding of Singletons的完整描述。

並非所有的GCD塊都是異步運行的。

+11

Kevin's是一個更好的答案,但我要離開我的鏈接到Mike Ash的帖子。 – Abizern 2012-02-02 20:07:38

相關問題