45

我用兩個GCD和performSelectorOnMainThread:我的應用程序waitUntilDone,並傾向於認爲他們是可以互換的 - 那就是,performSelectorOnMainThread:waitUntilDone是一個OBJ -C封裝到GCD C語法。我一直在想這兩個命令的等同:大中央調度(GCD)與performSelector - 需要一個更好的解釋

dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; }); 


[self performSelectorOnMainThread:@selector(doit:) withObject:YES waitUntilDone:YES]; 

上午我不正確的?也就是說,performSelector *命令與GCD命令有什麼不同?我已經閱讀了很多關於它們的文檔,但還沒有看到明確的答案。

+5

withObject:YES是行不通的,應該給您至少一個警告。這可能是GDC的一個優勢,您可以在其中向接收方發送任意參數。 – FelixLam 2011-03-07 21:00:54

+0

對,我需要將其包裝在NSNumber中。但是,忽略這一部分,其他的不同?好點,但。 – akaru 2011-03-07 21:18:09

回答

20

performSelectorOnMainThread:確實不是使用GCD將消息發送到主線程上的對象。

這裏的documentation怎麼說的方法來實現:

- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait { 
    [[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes]; 
} 

而且在performSelector:target:withObject:order:modes:,該文件規定:

這種方法建立了一個定時器上執行aSelector消息當前線程的在下一次運行循環迭代開始時運行循環。定時器配置爲以modes參數指定的模式運行。當定時器觸發時,線程將嘗試從運行循環中出列消息並執行選擇器。如果運行循環正在運行並處於指定模式之一,則成功;否則,定時器會等待,直到運行循環處於其中一種模式。

65

正如Jacob指出的那樣,雖然它們可能看起來相同,但它們是不同的東西。事實上,如果您已經在主線程上運行,那麼它們處理髮送操作到主線程的方式有很大的不同。

我遇到了這個最近,我在那裏,有時是從主線程上運行一些常用的方法,有時沒有。爲了保護某些UI更新,我一直在使用-performSelectorOnMainThread:,沒有任何問題。

當我切換到主隊列使用dispatch_sync,每當這個方法在主隊列中運行的應用程序將發生死鎖。在dispatch_sync閱讀文檔,我們可以看到:

調用此功能和定位 在僵局當前隊列結果。

其中用於-performSelectorOnMainThread:我們看到

等待

一個布爾指定是否 當前線程塊的主線程上的 接收機執行的 指定選擇後直到。指定 YES以阻止此線程;否則, 指定「否」,立即返回 。

如果當前線程也是主線程 ,並且您爲此 參數指定YES,則會將郵件發送到 並立即處理。

我還是比較喜歡GCD的風采,更好的編譯時檢查它提供的,其有關參數等更大的靈活性,所以我做了這個小助手功能,以防止死鎖:

void runOnMainQueueWithoutDeadlocking(void (^block)(void)) 
{ 
    if ([NSThread isMainThread]) 
    { 
     block(); 
    } 
    else 
    { 
     dispatch_sync(dispatch_get_main_queue(), block); 
    } 
} 

更新:針對戴夫Dribin指出的caveats section ondispatch_get_current_queue(),我已經改變了在上面的代碼使用[NSThread isMainThread]

然後我用

runOnMainQueueWithoutDeadlocking(^{ 
    //Do stuff 
}); 

執行我需要保證在主線程的操作,而不用擔心線程執行的原始方法。

+1

@Joe - 'dispatch_sync()'主線程仍有可能導致死鎖在應用程序中,如果在主線程上的東西被擋在值等待從後臺線程(通過'dispatch_sync()'或別的東西)。這是不太可能的,但仍然有可能。這是兩個線程的標準線程問題,等待另一個線程去做某件事,因此沒有任何事情可以完成。 – 2011-03-27 21:07:28

+0

@Joe - 是的,如果您完全在非主隊列或線程上運行,則不需要上面的代碼。剛纔我提到的死鎖問題也是這個代碼的問題。這更像是一個架構問題。至於評論去,看到這個元問題:http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work。 – 2011-03-27 21:26:23

+11

Pedantry溢出:你可以使用'dispatch_block_t'作爲參數類型來代替醜陋的'void(^ block)(void)'。 – 2011-08-01 00:19:45

1

GCD的方式是假設更有效率,更容易處理,而且只在iOS4的開始,而performSelector在新舊iOS的支持。