最近在阅读 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 就是从判断是否在主线程执行改为判断是否由主队列上调度。而由于主队列是一个串行队列,无论任务是异步同步都不会开辟新线程,所以当前队列是主队列等价于当前在主线程上执行。可以这样说,在主队列调度的任务肯定在主线程执行,而在主线程执行的任务不一定是由主队列调度的。
参考资料