主队列上的performSelectorOnMainThread和dispatch_async有什么区别?

时间:2012-02-17 21:10:15

标签: objective-c ios multithreading uikit grand-central-dispatch

我在修改线程内的视图时遇到问题。我试图添加一个子视图,但显示大约需要6秒或更长时间。我终于搞定了,但我不知道究竟是怎么回事。所以我想知道为什么它有效,以下方法之间有什么区别:

//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 Handler中调用的。

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

编辑:当我说它不起作用时,我意味着显示我添加的视图大约需要6秒钟。

3 个答案:

答案 0 :(得分:70)

默认情况下,-performSelectorOnMainThread:withObject:waitUntilDone:仅调度选择器以默认的运行循环模式运行。如果运行循环处于另一种模式(例如跟踪模式),则在运行循环切换回默认模式之前它不会运行。您可以使用变体-performSelectorOnMainThread:withObject:waitUntilDone:modes:解决此问题(通过传递您希望它运行的所有模式)。

另一方面,只要主运行循环将控制流返回到事件循环,dispatch_async(dispatch_get_main_queue(), ^{ ... })将运行该块。它不关心模式。因此,如果您不想关心模式,dispatch_async()可能是更好的方法。

答案 1 :(得分:1)

可能是因为performSelectorOnMainThread:withObject:waitUntilDone:使用常见的运行循环模式对消息进行排队。根据{{​​3}},主队列将把排队的任务与应用程序运行循环中的其他事件交错。因此,如果事件队列中还有其他要处理的事件,则可以先运行调度队列中的排队块,即使它们是稍后提交的。

Apple's Concurrency Programming Guide是对performSelectorOnMainThreaddispatch_async的绝佳解释,它也回答了上述问题。

答案 2 :(得分:0)

您是否使用PerformSelectorOnMainThread

尝试了waitUntilDone=YES

例如:

<强>代码:

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

我认为这可能会解决为什么PerformSelectorOnMainThread需要这么长时间来回应的问题。