上一篇的缓存策略主要说到二级缓存。这一部分将谈及下载。
SDWebImageManager 调用
首先看 SDWebImageManager 中的方法:
1 |
|
它会通过其属性 imageLoader 去创建一个下载用的 operation。这个 imageLoader 属性的定义如下,它会满足 SDImageLoader 协议:
1 | @property (strong, nonatomic, readonly, nonnull) id<SDImageLoader> imageLoader; |
在初始化 SDWebImageManager 的时候对其进行了设置,它默认是 SDWebImageDownloader 的实例。
SDWebImageDownloader
初始化方法
SDWebImageDownloader 也是一个单例对象,它的初始化方法如下:
1 | - (instancetype)initWithConfig:(SDWebImageDownloaderConfig *)config { |
初始化了一个 NSURLSession,并且设置了部分 header。
外部调用方法
外部调用的方法如下,它先对 options 做了一个简单的处理:
1 |
|
创建 SDWebImageDownloadToken
SDWebImageDownloadToken 类型的实例就是保存在 SDWebImageCombinedOperation 中的 loaderOperation。先看一下它的实例对象:
1 | @interface SDWebImageDownloadToken () |
可以看到它的内部包含一个 NSOperation 和 cancelled 实例。可以看出,他是 NSOperation 的包装类。来看一下它的创建过程:
1 | - (nullable SDWebImageDownloadToken *)downloadImageWithURL:(nullable NSURL *)url |
SDWebImageDownloader 是一个单例对象,它的内部包含了一个 URLOpeartion 的字典,保存着 url → NSOpeartion 的映射。当重复请求同一个正在请求的 url 的时候,就可以将回调方法保存在 NSOperation 的特定数组中,可以通过创建的 downloadOperationCancelToken 找到它,在特定的时候销毁或取消。
先不谈 NSOperation 是如何创建的,当它被创建之后,会被包裹在 SDWebImageDownloadToken 实例中,同样还包括 downloadOperationCancelToken。通过 downloadOperationCancelToken 可以取消某一个回调。
SDWebImageDownloaderOperation
SDWebImageDownloaderOperation 是 NSOperation 的子类,负责异步下载。
创建 NSOperation
1 |
|
SDWebImage 中充分利用了协议代替继承。这里需要创建的是一个实现了 SDWebImageDownloaderOperation 协议的 NSOperation:
1 | @protocol SDWebImageDownloaderOperation <NSURLSessionTaskDelegate, NSURLSessionDataDelegate> |
在 SDWebImage 中,默认的实现类是 SDWebImageDownloaderOperation。
开始执行
当 NSOperation 通过 addOpeartion 被添加到 NSOperationQueue 的时候,就会触发 NSOperation 的 start 方法:
1 |
|
在 start 方法中,创建并保存了 NSURLSession 实例,然后通过它创建并开启了 NSURLSessionTask。
beginBackgroundTaskWithExpirationHandler 不是意味着立即执行后台任务,它相当于注册了一个后台任务,而之后的 handler 表示 App 在直到后台运行的时机到来后在运行其中的 block 代码逻辑。
NSURLSessionDataDelegate
SDWebImageDownloaderOperation 是 NSURLSession 的 NSURLSessionDataDelegate。首先看第一次收到数据后的回调方法:
1 | /// 收到数据后第一次回调 |
首先是获取期望的数据大小 expectedContentLength,随后通过 statusCode 判断是否可以接收 data。调用了 completionHander 之后,进入下一个代码方法:
1 | /// 收到数据 |
不断的接收 data,并且将 data append 到 imageData 之后。如果是渐进式的加载方式,还需要变下载边解码。
下载好之后,会有一个回调判断是否要通过 NSURLCache 缓存数据:
1 | /// 判断是否可以缓存 response 的回调 |
NSURLSessionTaskDelegate
在下载完成后会回调 NSURLSessionTaskDelegate 的完成方法。在这里可以将获取的 data 通过回调函数回传给 Manager:
1 | /// 完成回调 |
至此,下载部分就结束了
总结
总的来说就是通过 SDWebImageDownloader 这个单例对象为每个请求创建一个 SDWebImageDownloadToken 实例来管理下载。同时 SDWebImageDownloader 也会保存每一个下载任务以供取消。SDWebImageDownloadToken 中又包含 SWDweImageDownloaderOperation 这个 NSOperation 的子类,用于真正的下载。