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

Ela*_*hts 14 asynchronous objective-c nsthread grand-central-dispatch ios

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

要在主线程上执行"stuff",我应该使用dispatch_async还是performSelectorOnMainThread?是否有首选方式,正确/错误和/或最佳做法?

示例:我在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];
        });
    }
}];
Run Code Online (Sandbox Code Playgroud)

在同一个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];
    }
}];
Run Code Online (Sandbox Code Playgroud)

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

tor*_*ons 14

正如Josh Caswell提供的链接中所提到的,这两者几乎相同.最显着的区别是,performSelectorOnMainThread只会在默认的运行循环模式下执行,并且如果运行循环在跟踪或其他模式下运行,则会等待.但是,编写和维护代码存在一些显着差异.

  1. dispatch_async具有编译器执行所有常规测试的巨大优势.如果您performSelectorOnMainThread在运行时错误地键入了该方法,而不是编译时间.
  2. dispatch_async使用__block限定符可以更容易地从主线程返回数据.
  3. dispatch_async使得处理原始参数变得更加容易,因为您不必将它们包装在对象中.然而,这带来了潜在的陷阱.如果您有指向某些数据的指针,请记住块捕获不会深度复制数据.另一方面,将数据包装在对象中,就像强制执行performSelectorOnMainThread深度复制一样(除非您设置了特殊选项).如果没有深层复制,您可能会遇到令人沮丧的间歇性错误.所以这意味着你应该char *NSString打电话之前把东西包裹起来dispatch_async.