SDWebImageManager 源码阅读记录(二)
我们利用SDWebImageManager能做很多其他的有意思的事情。比如给各种view绑定一个URL,就能显示图片的功能,有了Options,就能满足多种应用场景的图片下载任务。管理Cache和Downloader等。
目录
在 SDWebImageManager.h 中你可以看到关于 SDWebImageManager 的描述:
The SDWebImageManager is the class behind the UIImageView+WebCache category and likes. It ties the asynchronous downloader (SDWebImageDownloader) with the image cache store (SDImageCache). You can use this class directly to benefit from web image downloading with caching in another context than a UIView.
可以看到, 这个类的主要作用就是为 UIImageView+WebCache 和 SDWebImageDownloader, SDImageCache 之间构建一个桥梁, 使它们能够更好的协同工作, 我们在这里分析这个核心方法的源代码, 它是如何协调异步下载和图片缓存的.
SDWebImageManager核心
我们去看 SDWebImageManager 的核心方法
|
|
我们看这个方法前几句:
|
|
这块代码的功能是确定 url 是否被正确传入, 如果传入参数的是 NSString 类型就会被转换为 NSURL. 如果转换失败, 那么 url 会被赋值为空, 这个下载的操作就会出错.
|
|
当 url 被正确传入之后, 会实例一个非常奇怪的 “operation”, 它其实是一个遵循 SDWebImageOperation 协议的 NSObject 的子类. 这个类的作用是管理多个模块的取消操作,具体是怎么实现的,后面的代码会提到,__weak 修饰是为了防止循环引用。
下面就是文章最开始提到的功能之一,不可用的 URL 不会一次次重试的功能实现:
|
|
在 downloader 的下载方法的 completedBlock 中会将下载失败的 URL ,维护到 Set 集合中(黑名单),代码会在后面提到。这段代码的意思是如果发现 url 长度为 0 ,或者是下载失败过的 url ,且没有要求重试则直接创建 NSError 并 回调 completedBlock 。
|
|
manager 维护了一个数组 self.runningOperations ,将所有操作放进去,便于管理。(比如统一调用 cancel )下面是比较核心的代码:
|
|
通过 url 获取用来缓存的 key,尝试去缓存中取图片。queryDiskCacheForKey: done: 方法返回了一个 NSOperation 对象并赋值给了 SDWebImageCombinedOperation 的 cacheOperation ,这个类(SDWebImageCombinedOperation)中还有一个属性 cancelBlock 也会包括一些取消操作。它还实现了协议 <SDWebImageOperation> ,这个协议里只需要实现一个方法,就是 - (void)cancel; 。
|
|
而 SDWebImageCombinedOperation 的实现类中,实现了这个 cancel 方法,并调用了这些取消操作。
|
|
这样,调用者只要调用 operation 的 cancel(),就可以统一对多个模块类做取消操作。
然后看下查询缓存的方法 - (NSOperation *)queryDiskCacheForKey: done: 的实现代码:
|
|
会先到内存缓存中去查找,如果命中则直接回调,没有命中继续在磁盘缓存中查找。查找任务是异步的,在一个串行队列中,先生成一个 NSOperation 对象返回,也就是赋值给了 operation.cacheOperation 。在查找任务中,会先检测这个 operation 有没有被取消,如果取消则直接 return,这就实现了 SDWebImageCombinedOperation 可以取消查找缓存的操作。之后的代码就是去磁盘缓存中查找图片,且如果需要内存缓存就存进去,最后回调 doneBlock。这段代码被放入到了 @autoreleasepool 中包裹起来,是因为查找出来的图片可能会比较大,占用较多的内存,保障能够及时的回收它。
现在回到 SDWebImageManager 中继续看,在 queryDiskCacheForKey: 的 doneBlock 中,
|
|
如果操作被取消,则删除掉 self.runningOperations 的操作,然后 return。
接下来会有三个条件分支,我们一个个来看,第一个是:
|
|
image 为空意味着缓存没有命中,SDWebImageRefreshCached 则是就算缓存命中也要下载图片更新缓存,SDWebImageManager 这个类还定义了一个协议并实现一个代理。
|
|
第一个方法的意思是,是否下载图片,YES 就是下载,NO 就是不下载。第二个方法是,对下载好的图片 image 做 transform 处理,比如可以改成圆角图片等,然后返回,这样缓存的图片也会是 transform 之后的图片。
理解了代理方法的意思就可以理解这个条件了,如果缓存没有命中,或需要刷新已有缓存 且 没有实现 imageManager:shouldDownloadImageForURL 的方法(默认是 YES,可以下载图片)则去下载图片。如果实现了这个代理方法返回的是 YES,也会去下载图片。
看第一个条件里的代码,首先:
|
|
缓存如果命中,且需要更新缓存,则先将缓存图片通过 completedBlock 回调出去,在继续下载图片。在往下就是缓存没有命中或需要更新缓存的情况,所以需要下载图片,但之前先将SDWebImageManager 里 option 的条件映射成 SDWebImageDownloder 里的 option 的条件,下载使用的方法是 SDWebImageDownloder 里下面这个方法。
具体实现会在分析 SDWebImageDownloader 源码阅读记录(三) 时会说,我们先看 completedBlock 里的逻辑。
|
|
这里注意避免循环引用,imageDownloader 被 SDWebImageManager 强引用,downloadImageWithURL 的 completedBlock 会被 imageDownloader 的属性 URLCallbacks 数组强引用保存起来,至于为什么这么做后面会讲到。
然后是发生错误的处理情况:
|
|
发生错误,并回调。将在确定条件下失败的 URL 放入黑名单,不会反复请求。(通常是 URL 的问题,而不是网络问题)看下 else 之后的代码,稍长一些:
|
|
如果 option 是 SDWebImageRetryFailed 则这个 url 从黑名单中删除,给它一个重试的机会。有 downloadedImage 说明图片下载成功,如果是要进行 transform ,则调用 delegate 方法,获取 transform 之后的图片,进行缓存,再调用 completedBlock 。如果不需要 transform 则直接缓存后回调 completedBlock。
|
|
这是下载图片的取消操作,调用 NSOperation 的 cancel,从 self.runningOperations 中删除 operation。赋值给 cancelBlock ,交给 SDWebImageCombinedOperation 对象管理。
看前面提到的三个分支条件的第二个:
|
|
有 image 说明缓存命中,且没有要重下图片的情况,则直接回调 completedBlock 就可以了。
第三个分支条件,它的意思是既没有缓存图片,代理 delegate 也不允许下载图片,那就只能直接回调 completedBlock ,图片参数传 nil 了。
|
|
到此,SDWebImageManager 的核心方法:
|
|
就介绍完了。
最后是这个完整核心方法注释
|
|
其他
SDWenImageManager属性
|
|
SDWebImageOptions
SDWebImageOptions作为下载的选项提供了非常多的子项,用法和注意事项我都写在代码的注释中了:
|
|
SDWenImageManager初始化方法
|
|
cacheKeyForURL
|
|
检查图片是否缓存
|
|
下面两个方法比较类似,都是先根据图片的url创建对应的key第一个方法先用BOOL isInMemoryCache = ([self.imageCache imageFromMemoryCacheForKey:key] != nil);判断图片有没有在内存缓存中,如果图片在内存缓存中存在,就在主线程里面回调block,如果图片没有在内存缓存中就去查找是不是在磁盘缓存里面,然后在主线程里面回到block,第二个方法只查询图片是否在磁盘缓存里面,然后在主线程里面回调block
|
|
相关阅读:
SDWebImage 源码阅读记录(一)
SDWebImageManager 源码阅读记录(二)
SDWebImageDownloader 源码阅读记录(三)
SDWebImageDownloaderOperation 源码阅读记录(四)
SDWebImageCache 源码阅读记录(五)
SDWebImage相关类 源码阅读记录(六)