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

时间:2012-07-17 20:04:50

标签: ios objective-c asynchronous grand-central-dispatch nsthread

  

可能重复:
  Grand Central Dispatch (GCD) vs. performSelector - need a better explanation

要在主线程上执行“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];
        });
    }
}];

在同一个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];
    }
}];

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

1 个答案:

答案 0 :(得分:14)

正如乔什卡斯韦尔提供的链接中所提到的,这两者几乎相同。最值得注意的差异是performSelectorOnMainThread只会在默认的运行循环模式下执行,并且如果运行循环在跟踪或其他模式下运行,它将等待。但是,编写和维护代码存在一些显着差异。

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