如何确保我的功能仅在主线程上运行? (它更新UI元素)
这样的功能被认为是“坏”吗?
-(void)updateSomethingOnMainThread {
if ( ![[NSThread currentThread] isEqual:[NSThread mainThread]] )
[self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];
else {
// Do stuff on main thread
}
}
我这样写是为了避免使用第二个功能,最初我就是这样:
-(void)updateSomethingOnMainThread_real {
// Do stuff on main thread
}
-(void)updateSomethingOnMainThread {
[self performSelectorOnMainThread:@selector(updateSomethingOnMainThread_real) withObject:nil waitUntilDone:NO];
}
答案 0 :(得分:15)
作为ayoy基于方法的GCD实现的替代方案,用于保证在主线程上的执行,我在代码中使用了以下基于GCD的函数(来自another answer of mine):
void runOnMainThreadWithoutDeadlocking(void (^block)(void))
{
if ([NSThread isMainThread])
{
block();
}
else
{
dispatch_sync(dispatch_get_main_queue(), block);
}
}
然后,您可以在代码中的任何位置使用此辅助函数:
runOnMainThreadWithoutDeadlocking(^{
// Do stuff that needs to be on the main thread
});
这保证了封闭块中的操作将始终在主线程上运行,无论哪个线程调用它。它添加了很少的代码,并且明确指出需要在主线程上运行哪些代码。
答案 1 :(得分:8)
答案 2 :(得分:5)
我写了这个简单的#define,我一直在使用它取得了巨大的成功:
#define ensureInMainThread(); if (!NSThread.isMainThread) { [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO]; return; }
这样你的方法,假设它是无参数的,看起来像这样
- (void) updateTheThings {
ensureInMainThread();
[self.dog setTailWag:YES];
// etc...
答案 3 :(得分:3)
或者,您可以使用Grand Central Dispatch API,但这不是很方便:
-(void)updateSomethingOnMainThread {
void (^doStuff)(void) = ^{
// stuff to be done
};
// this check avoids possible deadlock resulting from
// calling dispatch_sync() on the same queue as current one
dispatch_queue_t mainQueue = dispatch_get_main_queue();
if (mainQueue == dispatch_get_current_queue()) {
// execute code in place
doStuff();
} else {
// dispatch doStuff() to main queue
dispatch_sync(mainQueue, doStuff);
}
}
否则,如果不需要同步呼叫,您可以调用更简单的dispatch_async()
:
-(void)updateSomethingOnMainThread {
dispatch_async(dispatch_get_main_queue(), ^{
// do stuff
});
}