Kingfisher源码分析
普通姿势
1 | // 普通姿势1 |
上面是两种普通设置网络图片的方法,弊端也是很明显的,originMethod1 会阻塞主线程,并且它们都没办法中途取消任务。
Kingfisher
以 Kingfisher v5.6.0 版本代码为示例
简单使用
1 | let url = URL(string: imageURL) |
kf 定义
先看 kf 的定义,返回一个包含自己的 KingfisherWrapper 对象,可以调用 Setting Image 一系列函数。
1 | extension ImageView: KingfisherCompatible { } |
setImage(with: resource…)
1 |
|
@discardableResult:表示取消不使用返回值的警告
可以看到 setImage(with: url) 内部调用了另外一个相似函数,只不过 source 参数类型从 Resource? 变成 Source? ,我们来看下这两者的区别:
1 | public protocol Resource { |
Resource 是协议,Source 是枚举,Source 有两种类型:.network(Resource) 和 .provider(ImageDataProvider)
imageView.kf.setImage(with: url) 可以直接传入 url,是因为 URL 实现了 Resource 协议
1 | extension URL: Resource { |
setImage(with: source…)
1 |
|
KingfisherManager.shared.retrieveImage(with: source…)
1 | func retrieveImage( |
从缓存中获取图片: retrieveImageFromCache(source: Source…)
1 | func retrieveImageFromCache( |
下载并缓存图片: loadAndCacheImage(source…)
1 |
|
创建 DownloadTask: downloadImage(with url…)
1 |
|
下载这步看着有点绕,我们来梳理一下:
- ImageDownloader 是下载管理器,这个类中包含 session、sessionDelegate 等
- SessionDelegate 是 URLSession 的 delegate,这个类中包含 tasks, 类型是 [URL: SessionDataTask],以及实现 URLSessionDataDelegate 相关协议
- SessionDataTask 是 URLSessionDataTask 的封装,里面包含了 task、callbacksStore,callbacksStore 是 task 对应的多个回调
当 sessionTask.resume() 开始下载时,SessionDelegate 就开始接受数据,接受完数据后,会调用 urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 协议,然后再调用 onCompleted(task: URLSessionTask, result: Result<(Data, URLResponse?), KingfisherError>) 方法,找到对应的 sessionTask,执行 sessionTask 的 onTaskDone 回调,传入 result 和 callbacks。
1 | func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { |
Data 转换为 Image: process(item: ImageProcessItem…)
可以看到是通过 Image(data: data, scale: options.scale) 方法生成对应图片
通过 Data 前面的 bytes 判断图片对应的格式
1 | public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> Image? { |
缓存图片 store(_ image: Image…)
1 | open func store(_ image: Image, |
完整流程
补充
缓存策略
内存缓存:
MemoryStorage.Backend 类中有一个 cleanTimer 定时器,默认时间是 120s 去清理一次过期图片,图片的默认过期时间是 300s。如果从缓存中取到了图片,就重置该图片的开始时间,默认过期时间依然是 300s。
磁盘缓存:
图片的默认过期时间是 7天,如果从磁盘中取到了图片,就重置该图片的开始时间,默认过期时间依然是 7天。
其它细节
ImageCache 类中添加了一系列的监听通知,比如 App 收到内存警告时,所以当 App 收到内存警告时,不需要再次处理图片缓存。
1
2
3
4
5
6
7
8
9notifications = [
(UIApplication.didReceiveMemoryWarningNotification, #selector(clearMemoryCache)),
(UIApplication.willTerminateNotification, #selector(cleanExpiredDiskCache)),
(UIApplication.didEnterBackgroundNotification, #selector(backgroundCleanExpiredDiskCache))
]
notifications.forEach {
NotificationCenter.default.addObserver(self, selector: $0.1, name: $0.0, object: nil)
}