关于 dispatch_main_async_safe

关于 dispatch_main_async_safe_第1张图片

最近在阅读 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

你可能感兴趣的:(关于 dispatch_main_async_safe)