今天在阅读 SDWebImage 的源码,发现了这段有趣的代码。
SDWebImage这个库里的一段宏定义代码:
先对这段代码做一个简单的解读。显然 #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 就是从判断是否在主线程执行改为判断是否由主队列上调度。而由于主队列是一个串行队列,无论任务是异步同步都不会开辟新线程,所以当前队列是主队列等价于当前在主线程上执行。可以这样说,在主队列调度的任务肯定在主线程执行,而在主线程执行的任务不一定是由主队列调度的。
下面通过自己写的demo来帮助理解
当在子线程中调用setImageUrl方法时会发现先走block外面也就是先输出2222.
当在主线程中调用时会先走block里面。
当你需要dispatch_async(dispatch_get_main_queue(), blockSD);获取主线程的时候 也就是执行非主队列调度API,而这个API需要检查是否由主队列上调度,那么将会出现问题。所以需要先判断当前是否在主线程。
学习能让你快乐 快乐你就拍拍手。