SDWebImage5.5.1 源码探究

一、SDWebImage 如何保证UI操作放在主线程中执行?

iOS UI 操作在主线程不一定安全?

 

为什么dispatch_get_current_queue被废弃?

https://www.jianshu.com/p/f73ca215268d

 

在SDWebImage的SDWebImageCompat.h中有这样一个宏定义,用来保证主线程操作,为什么要这样写?

 

// SDWebImageCompat.h 中

#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

Queues are not bound to any specific thread

分析:如何判断当前是否在main thread?

最简单的方法

检查我们当前在主线程上执行的最简单的方法是使用[NSThread isMainThread] - GCD缺少一个类似的方便的API来检查我们是否在主队列上运行,因此许多开发人员使用了NSThread API。如下:

 

if ([NSThread isMainThread]) {
    block();
} else {
    dispatch_async(dispatch_get_main_queue(), block);
}

这在大多数情况下是有效的,直到它出现了异常。下面是关于ReactiveCocoa repo问题的摘录:
ReactiveCocoa issue

image

潜在的问题是VektorKit API正在检查是否在主队列上调用它,而不是检查它在主线程上运行。

虽然每个应用程序都只有一个主线程,但是在这个主线程上执行许多不同的队列是可能的。

如果库(如VektorKit)依赖于在主队列上检查执行,那么从主线程上执行的非主队列调用API将导致问题。也就是说,如果在主线程执行非主队列调度的API,而这个API需要检查是否由主队列上调度,那么将会出现问题。

更安全的方法一

从技术上讲,我认为这是一个 MapKit / VektorKit 漏洞,苹果的UI框架通常保证在从主线程调用时正确工作,没有任何文档提到需要在主队列上执行代码。

但是,现在我们知道某些api不仅依赖于主线程上的运行,而且还依赖于主队列,因此检查当前队列而不是检查当前线程更安全。

检查当前队列还可以更好地利用GCD为线程提供的抽象。从技术上讲,我们不应该知道/关心主队列是一种总是绑定到主线程的特殊队列。

不幸的是,GCD没有一个非常方便的API来检查我们当前正在运行的队列(这很可能是许多开发人员首先使用NSThread.isMainThread()的原因)。

我们需要使用 dispatch_queue_set_specific 函数来将键值对与主队列相关联;稍后,我们可以使用 dispatch_queue_get_specific 来检查键和值的存在。

 

- (void)function {
    static void *mainQueueKey = "mainQueueKey";
    dispatch_queue_set_specific(dispatch_get_main_queue(), mainQueueKey,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值