sd_setImageWithURL
方法,来分析源码。而在其中,对于图片的 download 方法,也是需要理解的重点之一。它用于处理异步下载和图片缓存的类,当然也可直接拿来使用。SDWebImageManager
这个类,为 WebCache
、 SDWebImageDownloader
和 SDImageCache
搭建了一个桥梁,使得拥有更好的协同性。而每个类负责的功能不同,又是通过该类进行了结构上的解耦。这篇通过分析 SDWebImageManager
的 Source Code ,来深入分析一下 SD 三方库中,对于 download 方法具体实现细节。
缓存策略一览
在 WebCache 的 sd_setImageWithURL 方法中的缓存策略,调用了这个方法:
1 2 3 4 |
- (id SDWebImageOperation>)downloadImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionWithFinishedBlock)completedBlock; |
参数解释:
- url:image 对应的 url
- options:缓存策略枚举
- progress:在 download 过程中的动作,block 实现
- completed:在 download 完成后的动作,block 实现
在查看方法之前,先来查看一下缓存策略枚举(options)是如何定义的,在源码中作者已经在注释里描述了每一种枚举代表的含义,这里笔者翻译了一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { // 下载失败后会继续尝试下载 SDWebImageRetryFailed = 1 0, // 当正在进行 UI 交互时,自动暂停内部的一些下载操作 // 一种延迟下载策略。比如在 UIScrollView 快速滑动的时候暂停下载 // 但是当滑动速度减慢时,下载开始 SDWebImageLowPriority = 1 1, // 只进行内存缓存,不缓存到硬盘 SDWebImageCacheMemoryOnly = 1 2, // 渐进式下载模式 // 图像会像 brower 一样,一点点加载出来 SDWebImageProgressiveDownload = 1 3, // 刷新缓存 // 将硬盘缓存交给硬盘自带的 NSURLCache 处理 // 当同一个 URL 对应的图片频繁改变的时候,可以使用该策略 SDWebImageRefreshCached = 1 4, // 后台下载,试用与 iOS 4+ 系统中 SDWebImageContinueInBackground = 1 5, // 设置 NSMutableURLRequest.HTTPShouldHandleCookies = YES; // 从而来处理存储在 NSHTTPCookieStore 的 cookie SDWebImageHandleCookies = 1 6, // 允许无效的 SSL 检验 SDWebImageAllowInvalidSSLCertificates = 1 7, // 使用高级别的线程权限,默认是等待当前线程完成再进行 SDWebImageHighPriority = 1 8, // 默认情况向,当网络图片加载时占位图片(place holder)显示。 // 若采用此策略,则不会显示占位图片,直到网络图片加载完成后,如果失败则使用占位图片 SDWebImageDelayPlaceholder = 1 9, // 是否 transform 图片 // 常作为 transformdownloadedimage 代理方法的替代 // 防止对图片解析时的破坏 SDWebImageTransformAnimatedImage = 1 10, // 下载完成后,手动设置图片 // 一般默认情况下,下载完成会自动加载到 ImageView 上 SDWebImageAvoidAutoSetImage = 1 11 }; |
Manage Download Image 主要流程
了解了所有的下载策略,开始阅读实现的源码。
1 2 3 |
if ([url isKindOfClass:NSString.class]) { url = [NSURL URLWithString:(NSString *)url]; } |
首先,先考虑到了传递参数 url 类型为 NSString 的情况,在注释中,作者这样写道:
没有传递 NSURL ,而是使用 NSString 对象传递 url 是一个很常见的错误。由于一些奇怪的原因,Xcode 并不会抛出类型不匹配的警告。所以,我们于此允许传递 NSString 对象,并自动转换成 NSURL 从而保护该错误。
1 2 3 |
if (![url isKindOfClass:NSURL.class]) { url = nil; } |
仍是为了防止参数类型错误,对 url 的类型再次进行了判断。如果非法,则赋 nil 方便后面的排查。
1 2 |
__block SDWebImageCombinedOperation *operation = [SDWebImageCombinedOperation new]; __weak SDWebImageCombinedOperation *weakOperation = operation; |
当 url 合法性过滤过程完成后,发现了源码中会实例化 SDWebImageCombinedOperation
这么一个对象。这是继承与 NSObject
并遵循 SDWebImageOperation
协议的一个类。