确保函数仅在主线程上运行

时间:2011-10-21 16:58:58

标签: iphone objective-c

如何确保我的功能仅在主线程上运行? (它更新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];
}

4 个答案:

答案 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)

这很好。您还可以使用GCD在主线程上执行代码。

查看此SO帖子。

GCD to perform task in main thread

答案 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
    });
}