关于 dispatch_main_async_safe

作者 Tsui YuenHong 日期 2017-02-10
关于 dispatch_main_async_safe

最近在阅读 SDWebImage 的源码,发现了这段有趣的代码。

最新代码

#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block)\
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}
#endif

之前的代码,而且这是网上流传最多的代码。

#define dispatch_main_async_safe(block)\
if ([NSThread isMainThread]) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}

对比两段代码可以发现前者有两个地方改变了,一是多了 #ifndef,二是判断条件改变了。

显然,增加 #ifndef 是为了提高代码的严谨,防止重复定义 dispatch_main_async_safe

关于判断条件的改变的原因则是复杂得多了,具体可以阅读 GCD’s Main Queue vs. Main Thread

原文这样说道:

Calling an API from a non-main queue that is executing on the main thread will lead to issues if the library (like VektorKit) relies on checking for execution on the main queue.

意思大概是如果在主线程执行非主队列调度的API,而这个API需要检查是否由主队列上调度,那么将会出现问题。

SDWebImage 就是从判断是否在主线程执行改为判断是否由主队列上调度。而由于主队列是一个串行队列,无论任务是异步同步都不会开辟新线程,所以当前队列是主队列等价于当前在主线程上执行。可以这样说,在主队列调度的任务肯定在主线程执行,而在主线程执行的任务不一定是由主队列调度的。

参考资料

  1. SDWebImage 官方解释
  2. GCD’s Main Queue vs. Main Thread