可能重复:
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进行更改...如果有人想知道为什么我正在做我正在做的事情......
答案 0 :(得分:14)
正如乔什卡斯韦尔提供的链接中所提到的,这两者几乎相同。最值得注意的差异是performSelectorOnMainThread
只会在默认的运行循环模式下执行,并且如果运行循环在跟踪或其他模式下运行,它将等待。但是,编写和维护代码存在一些显着差异。
dispatch_async
具有编译器执行所有常规测试的巨大优势。如果您错误地键入performSelectorOnMainThread
中的方法,则在运行时失败,而不是编译时间。dispatch_async
使用__block
限定符更容易从主线程返回数据。dispatch_async
使得处理原始参数变得更加容易,因为您不必将它们包装在对象中。然而,这带来了潜在的陷阱。如果您有指向某些数据的指针,请记住块捕获不会深度复制数据。另一方面,将数据包装在对象中,就像强制为performSelectorOnMainThread
执行操作一样,会进行深层复制(除非您设置了特殊选项)。如果没有深层复制,您可能会遇到令人沮丧的间歇性错误。因此,这意味着在致电char *
之前,您应该在NSString
中包含dispatch_async
之类的内容。