SDWebImage使用时,url未变,但图片资源变化如何及时更新展示内容

面试官提问频率比较高的一个问题就是:如果同一url对应图片资源已经改变,当使用SDWebImage时该如何处理才能让图片及时刷新内容?

iOS 9以前,SD未能很好地处理此类问题,需要我们手动修改一下源码,网络上答案满天飞,举个比较常用的处理方法:

1、发起时这样调用方法

[self.imageView sd_setImageWithURL:[NSURL URLWithString:urlStr] placeholderImage:nil options:SDWebImageRefreshCached];

2、修改SDWebImage源码,需要找到SDWebImageManager.m, 178行代码处换行并追加代码

 downloaderOptions &= ~SDWebImageDownloaderUseNSURLCache;

用这个方法可以解决如上问题,但为什么呢?下面我们结合新老版本的SDWebImage源码来实实在在的看看到底为什么这么改就可以,根本原因是什么?

首先要清楚一点,SDWebImage的缓存策略,NSURLCache + SDWebImageCache(也就是SD自己的缓存机制)

NSURLCache会缓存网络请求结果,一旦某次开启了同样的请求并指定可以返回NSURLCache的缓存内容,那么会直接调用NSURLCache的缓存内容直接返回

而url对应内容变化,客户端未刷新的原因就在于请求时,不小心指定了使用NSURLCache的优化机制直接返回了内容,却并未发起请求,去获取最新资源

好了,接下来看源码,我找到的是3.7.6的SDWebImage老代码

image

这里是下载任务开启前的操作,一旦指定了options 包含了SDWebImageRefreshCached类型,downloaderOptions会被追加一个SDWebImageDownloaderUseNSURLCache类型,标志着可以启用NSURLCache机制

然后看下一张图


image

下载任务开启前,缓存策略经过一个枚举并运算赋值成了 NSURLRequestUseProtocolCachePolicy

再看另一张图


image

定位到SDWebImageDownloaderOperation.m 文件,可以看到当需要缓存请求返回结果的时候,有一个if逻辑,当指定了对应的属性后才会不缓存本次请求结果

结合以上三段源码我们就可以得到结论了:

sd_setImageWithUrl 时,虽然我们指定了SDWebImageRefreshCached操作,但相关逻辑执行后,会启用NSURLCache机制,并在拿到请求结果后被NSURLCache缓存起来,下次有相同请求进来时,会触发NSURLCache机制,返回之前请求的结果,所以,导致url未变,图片资源已变,但客户端展示未刷新问题

然而,iOS9之后SDWebImage因NSURLConnection被废弃缘故,改用推荐的NSURLSession,在这之后,如果面临url不变,资源改变的情况,再也不需要动手修改源码了,下面我们看看改版后的SD做了什么

image

改版后,这处代码做了优化,判断条件修改为除非用户 指定了要启用NSURLCache缓存机制,否则默认情况不允许缓存response,规避掉了相关问题

但是,这样看上去每一次都会重新开启下载任务去下载啊,岂不是造成了资源浪费。答案是否定的,这里就需要引入网络通信协议相关概念,Http、Https缓存机制中提供了验证机制,利用Last-Modified 或者Entity Tag(ET)来验证当前已缓存的资源是否与服务端最新资源相同。有兴趣的朋友可以去看一下RFC文档

所以,重写willCacheResponse方法时,虽然不允许缓存请求结果,但是再进行请求时,由于验证机制的存在,仍然避免了相同资源的重复请求

你可能感兴趣的:(SDWebImage使用时,url未变,但图片资源变化如何及时更新展示内容)