上一篇的缓存策略主要说到二级缓存。这一部分将谈及下载。
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 的子类,用于真正的下载。