ios 使用 dispatch_async 或 performSelectorOnMainThread 在主线程上执行 UI 更改?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11530050/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:17:40  来源:igfitidea点击:

Perform UI Changes on main thread using dispatch_async or performSelectorOnMainThread?

iosobjective-casynchronousgrand-central-dispatchnsthread

提问by ElasticThoughts

Possible Duplicate:
Grand Central Dispatch (GCD) vs. performSelector - need a better explanation

可能的重复:
Grand Central Dispatch (GCD) 与 performSelector - 需要更好的解释

To execute "stuff" on the main thread, should I use dispatch_asyncor performSelectorOnMainThread? Is there a preferred way, right/or wrong, and/or best practice?

要在主线程上执行“东西”,我应该使用dispatch_async还是performSelectorOnMainThread?是否有首选的方式,对/或错,和/或最佳实践?

Example: I'm performing some logic within the block of an NSURLConnection sendAsynchronousRequest:urlRequestmethod. Because I'm doing stuff to the main view such as presenting a UIAlertViewI need to show the UIAlertViewon the main thread. To do this I'm using the following code.

示例:我正在NSURLConnection sendAsynchronousRequest:urlRequest方法块内执行一些逻辑。因为我正在对主视图做一些事情,例如呈现UIAlertView我需要UIAlertView在主线程上显示的。为此,我使用以下代码。

[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

    // code snipped out to keep this question short

    if(![NSThread isMainThread]) 
    {
        dispatch_async(dispatch_get_main_queue(), ^{
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Oops!" message:@"Some Message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                    [alertView show];
        });
    }
}];

Within that same if(![NSThread isMainThread])statement I also call some custom methods. The question is, should I use the dispatch_asyncmethod that I'm using above or is it better to use performSelectorOnMainThreadinstead? For example, full code below:

在同一个if(![NSThread isMainThread])语句中,我还调用了一些自定义方法。问题是,我应该dispatch_async使用上面使用的方法还是performSelectorOnMainThread改用更好?例如,下面的完整代码:

[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {

    // code snipped out to keep this question short

    if(![NSThread isMainThread]) 
    {
        dispatch_async(dispatch_get_main_queue(), ^{
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Oops!" message:@"Some Message" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                    [alertView show];

            // call custom methods in dispatch_async?
            [self hideLoginSpinner];
        });

        // or call them here using performSelectorOnMainThread???
        [self performSelectorOnMainThread:@selector(hideLoginSpinner) withObject:nil waitUntilDone:NO];
    }
}];

FYI - If I DO NOT perform these actions on he main thread I see a few second delay when presenting the UIAlertViewand I receive the following message in the debugger wait_fences: failed to receive reply: 10004003. I've learned that this is because you need to make changes to the UI on the main thread... In case someone is wondering why I'm doing what I'm doing...

仅供参考 - 如果我不在主线程上执行这些操作UIAlertView,我会在显示时看到几秒钟的延迟,并且在调试器中收到以下消息wait_fences: failed to receive reply: 10004003。我了解到这是因为您需要对主线程上的 UI 进行更改...以防有人想知道我为什么要做我正在做的事情...

采纳答案by torrey.lyons

As mentioned in the links provided by Josh Caswell, the two are almost equivalent. The most notable differences is that performSelectorOnMainThreadwill only execute in the default run loop mode and will wait if the run loop is running in a tracking or other mode. However, there are some significant differences for writing and maintaining the code.

正如 Josh Caswell 提供的链接中提到的,两者几乎是等价的。最显着的区别是performSelectorOnMainThread只会在默认的 run loop 模式下执行,如果 run loop 在跟踪或其他模式下运行,它将等待。但是,编写和维护代码存在一些显着差异。

  1. dispatch_asynchas the big advantage that the compiler does all its usual tests. If you mistype the method in performSelectorOnMainThreadyou fail at run time, rather than compile time.
  2. dispatch_asyncmakes it much easier to return data from the main thread using the __blockqualifier.
  3. dispatch_asyncmakes it much easier to handle primitive arguments since you don't have to wrap them in an object. However, this comes with a potential pitfall. If you have a pointer to some data remember that block capture does not deep copy the data. On the other hand wrapping the data in an object as you would be forced to do for performSelectorOnMainThreaddoes deep copy (unless you set special options). Without a deep copy you can run into intermittent bugs that are frustrating to debug. So this means you should wrap things like char *in NSStringbefore you call dispatch_async.
  1. dispatch_async编译器进行所有常规测试的巨大优势。如果您performSelectorOnMainThread在运行时错误输入方法,而不是编译时失败。
  2. dispatch_async使用__block限定符从主线程返回数据变得更加容易。
  3. dispatch_async使处理原始参数变得更加容易,因为您不必将它们包装在一个对象中。然而,这有一个潜在的陷阱。如果你有一个指向某个数据记住块捕获不会将数据深层复制。另一方面,将数据包装在一个对象中,因为您将被迫执行performSelectorOnMainThread深度复制(除非您设置特殊选项)。如果没有深层复制,您可能会遇到令人沮丧的间歇性错误调试。所以这意味着你应该char *NSString调用dispatch_async.