2012-02-17 63 views
52

我在修改線程內的視圖時遇到問題。我試圖添加一個子視圖,但它需要大約6秒或更長時間來顯示。我終於搞定了,但我不知道具體如何。所以我想知道爲什麼它的工作,什麼是以下方法之間的區別:主隊列上的performSelectorOnMainThread和dispatch_async有什麼區別?

//this worked -added the view instantly 
dispatch_async(dispatch_get_main_queue(), ^{ 
    //some UI methods ej 
    [view addSubview: otherView]; 
} 

//this took around 6 or more seconds to display 
[viewController performSelectorOnMainThread:@selector(methodThatAddsSubview:) withObject:otherView 
waitUntilDone:NO]; 

//Also didnt work: NSNotification methods - took also around 6 seconds to display 
//the observer was in the viewController I wanted to modify 
//paired to a method to add a subview. 
[[NSNotificationCenter defaultCenter] postNotificationName: 
@"notification-identifier" object:object]; 

僅供參考這個被稱爲類的ACAccountStore的這個Completetion處理程序中。

accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) { 
      if(granted) { 
      //my methods were here 
      } 
} 

編輯:當我說它沒有工作,我的意思是大約需要6秒鐘來顯示我添加的視圖。

+0

當你說'performSelectorOnMainThread:'不起作用時,它是如何失敗的?你收到錯誤信息了嗎?它是一個運行時錯誤的編譯錯誤?如果你沒有得到一個錯誤,你怎麼知道它失敗了? – 2012-02-17 21:52:09

+0

是'addSubview:'您使用觸摸的UI元素的唯一方法,還是其他人? – 2012-02-17 21:52:38

+0

@AndrewMadsen我忘了提及它的工作原理,但大約需要6秒或更長的時間來顯示。 – 2012-02-17 22:16:34

回答

69

默認情況下,-performSelectorOnMainThread:withObject:waitUntilDone:只調度選擇器以默認運行循環模式運行。如果運行循環處於另一種模式(例如跟蹤模式),它將不會運行,直到運行循環切換回默認模式。你可以通過變種-performSelectorOnMainThread:withObject:waitUntilDone:modes:來解決這個問題(通過傳遞你希望它運行的所有模式)。

另一方面,dispatch_async(dispatch_get_main_queue(), ^{ ... })會在主運行循環返回控制流回到事件循環後立即運行該塊。它不關心模式。所以如果你不想關心模式,dispatch_async()可能是更好的方法。

+1

什麼是模式,我應該什麼時候關心它們? – ma11hew28 2014-01-22 16:05:26

+2

@MattDiPasquale:在iOS上,基本上可以忽略它們,runloop通常始終以默認模式運行。在OS X上,您可能會看到3種模式:「NSConnectionReplyMode」,「NSModalPanelRunLoopMode」和「NSEventTrackingRunLoopMode」。如果你有興趣,你可以查看這些文檔。 – 2014-01-22 21:13:55

+2

請注意,在iOS中,UITrackingRunLoopMode用於某些觸摸事件跟蹤(當UIScrollView正在跟蹤觸摸移動時)。 – cdemiris99 2014-02-18 01:08:03

0

你有沒有嘗試PerformSelectorOnMainThreadwaitUntilDone=YES

如:

代碼:

[viewController performSelectorOnMainThread:@selector(methodThatAddsSubview:) withObject:otherView waitUntilDone:YES]; 

我認爲這可能會解決這個問題作爲爲什麼PerformSelectorOnMainThread需要這麼長的時間作出反應。

1

很可能是因爲performSelectorOnMainThread:withObject:waitUntilDone:使用常見的運行循環模式排隊消息。根據Apple's Concurrency Programming Guide,主隊列將排隊的任務與來自應用運行循環的其他事件交織。因此,如果在事件隊列中還有其他事件要處理,則可以先運行派遣隊列中的排隊塊,儘管它們稍後提交。

This article是對performSelectorOnMainThreaddispatch_async的極好解釋,它也回答了上述問題。