Objective-C Gurus,
我一直在使用以下宏来确保在主线程上运行块。这个想法很简单:如果我目前在主线程上,那么我将立即运行该块。如果当前线程不是主线程,那么我将块排队以异步方式在主线程上运行(这样它就不会阻塞当前线程)。
你觉得这有什么问题吗?这里有什么不安全的,或导致我不知道的错误?有没有更好的方法呢?
#define run_on_main(blk) if ([NSThread isMainThread]) { blk(); } else { dispatch_async(dispatch_get_main_queue(), blk); }
示例用法:
-(BOOL)loginCompletedSuccessfully
{
NSLog(@"loginCompletedSuccessfully");
// This may be called from a network thread, so let's
// ensure the rest of this is running on the main thread.
run_on_main(^{
if (_appStartupType == AppLaunch) {
self.storyboard = [UIStoryboard storyboardWithName:DEVICED(@"XPCStoryboard") bundle:nil];
self.navigationController = [storyboard instantiateInitialViewController];
}
[self.window setRootViewController:self.navigationController];
});
return YES;
}
答案 0 :(得分:5)
这可能会导致执行顺序出现令人讨厌的微妙错误。
以这个简单的例子(在主线程上)
__block NSInteger integer = 5;
run_on_main(^{
integer += 10;
});
NSLog(@"From Main %d", integer);
这将打印结果15
相同的代码在后台线程中运行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
__block NSInteger integer = 5;
run_on_main(^{
integer += 10;
});
NSLog(@"From background %d", integer);
});
结果将是5
...或15
,具体取决于主题之间的竞争条件。
这种不一致可能会让你失望。
为什么不在两种情况下都使用dispatch_async
,并且知道两者现在都会表现出相同的行为。这是安全和正常的,因为您正在使用非阻塞的async
答案 1 :(得分:4)
与往常一样,如果有其他选项,请避免使用宏。在这种情况下,很容易使用函数:
static inline void run_on_main(dispatch_block_t block)
{
if ([NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
}
这相当于你的宏定义;你甚至可以把它放在同一个地方。优点是您可以获得编译器支持语法检查,块的Xcode语法完成(非常有用),调试时支持调试器等等。
Plus:run_on_main
在源代码中不显示为棕色;)