3

Objective-C 大师,

我一直在使用以下宏来确保一个块在主线程上运行。这个想法很简单:如果我当前在主线程上,那么我将立即运行该块。如果当前线程不是主线程,那么我将要在主线程上异步运行的块排队(这样它就不会阻塞当前线程)。

你觉得这有什么问题吗?这里有什么不安全的,或者导致我不知道的错误吗?有没有更好的方法来做到这一点?

#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;
}
4

2 回答 2

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的是非阻塞的

于 2013-03-20T17:12:27.403 回答
4

与往常一样,如果有其他选择,请避免使用宏。在这种情况下,很容易使用一个函数来代替:

static inline void run_on_main(dispatch_block_t block)
{
    if ([NSThread isMainThread]) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

这相当于你的宏定义;你甚至可以把它放在同一个地方。优点是您可以获得语法检查的编译器支持、块的 Xcode 语法完成(非常有用)、调试时的调试器支持等等。

另外:run_on_main在您的源代码中不会出现棕色;)

于 2013-03-20T16:59:56.623 回答