14

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

要在主线程上执行“东西”,我应该使用dispatch_asyncorperformSelectorOnMainThread吗?是否有首选方法、正确/错误和/或最佳实践?

示例:我正在方法块中执行一些逻辑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 进行更改...如果有人想知道我为什么要做我正在做的事情...

4

1 回答 1

14

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

  1. dispatch_async最大的优势是编译器会进行所有常规测试。如果您performSelectorOnMainThread在运行时错误地键入方法,而不是编译时失败。
  2. dispatch_async使用__block限定符从主线程返回数据变得更加容易。
  3. dispatch_async makes 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 performSelectorOnMainThread does 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 NSString before you call dispatch_async.
于 2012-07-17T23:02:17.743 回答