7

有沒有辦法模擬dispatch_apply()塊中的break語句?如何「突破」dispatch_apply()?

例如,每一個可可API我見過的處理列舉塊有一個「停止」參數:

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger i, BOOL *stop) { 
    if ([obj isNotVeryNice]) { 
     *stop = YES; // No more enumerating! 
    } else { 
     NSLog(@"%@ at %zu", obj, i); 
    } 
}]; 

是否有GCD類似的東西?

回答

4

我不認爲dispatch_apply支持這個。我能想到的模仿它的最好方法是創建一個__block布爾變量,並在塊的開頭檢查它。如果設定好了,快速退出。您仍然需要在迭代的其餘部分運行該塊,但速度會更快。

1

您不能break a dispatch_apply因爲它不合邏輯。

-enumerateObjectsUsingBlock:中斷是明確定義的,因爲函數按順序運行。但在dispatch_apply中,這些功能是並行運行的。這意味着在i=3 rd調用「塊」時,i=4調用可能已經啓動。如果你breaki=3i=4呼叫應該仍然運行?

@BJ的答案是最接近你可以做的,但總會有一些「溢出」。

+0

那麼,這並不完全正確;雖然enumerateObjectsUsingBlock:是順序的,但也有enumerateObjectsWithOptions:usingBlock :.該「選項」參數可用於指示枚舉應該同時發生。 我不確定他們是如何在內部做這件事的,但我想這是使用dispatch_group來完成的,這樣可以實現更直接的控制。 – 2010-06-23 21:53:35

+0

但問題是enumerateObjectsWithOptions:usingBlock:仍然有* stop參數。 – 2010-06-23 21:54:04

+1

支持在dispatch_apply()中停止是合乎邏輯的,但在設計目標中沒有意義。聲明'enumerateObjectsUsingBlock:'上的停止標誌因隱式順序執行而存在是錯誤的;這兩個是完全正交的。 – bbum 2010-06-23 23:23:36

14

按設計,dispatch_*() API沒有取消的概念。原因是因爲你的代碼保持停止或不停止的概念幾乎普遍適用,因此也支持在調度中_ *()API將是多餘的(並且冗餘會帶來錯誤)。因此,如果你想「停止提前」或以其他方式取消分派隊列中的待處理項目(不管它們是如何入隊的),你可以通過與入隊的分塊分享一些狀態來做到這一點,這允許你取消。

if (is_canceled()) return; 

或者:

__block BOOL keepGoing = YES; 
dispatch_*(someQueue, ^{ 
    if (!keepGoing) return; 
    if (weAreDoneNow) keepGoing = NO; 
} 

注意兩個enumerateObjectsUsingBlock:enumerateObjectsWithOptions:usingBlock:都支持取消,因爲API是在不同的作用。對枚舉方法的調用是同步即使枚舉塊的實際執行可能完全併發,具體取決於選項。

因此,設置*stopFlag=YES會告訴枚舉停止。但是,它並不保證它會立即停止併發情況。實際上,枚舉可能會在停止之前執行更多已排入隊列的塊。

(有人可能會簡單地認爲返回BOOL來指示枚舉是否應該繼續會更合理,這樣做會要求枚舉塊同步執行,即使在併發情況下也是如此,以便返回值這可能會大大降低效率。)