Kingfisher 源码解析系列,由于水平有限,哪里有错,肯请不吝赐教
- Kingfisher 源码解析之使用
- Kingfisher 源码解析之 Options 解释
- Kingfisher 源码解析之加载流程
- Kingfisher 源码解析之加载动图
- Kingfisher 源码解析之 ImageCache
- Kingfisher 源码解析之 Processor 和 CacheSerializer
- Kingfisher 源码解析之 ImagePrefetcher
本篇文章主要介绍 Processor 和 CacheSerializer 的基本定义和调用时机,以及利用二者扩展 Kingfisher 以支持 webp 格式的图片
Processor
Processor 介绍
Kingfisher 中 Processor 是一个协议,定义了对原始数据进行加工处理转换成 UIImage 的能力(Kingfisher 缓存的是处理成功之后的 UIImage,根据 options 的值来决定是否缓存原始数据)。
这里的原始数据是指 ImageProcessItem,它是一个枚举类型。Processor 和 ImageProcessItem 定义如下,都是特别简单
1 | public enum ImageProcessItem { |
2 | case image(KFCrossPlatformImage) |
3 | case data(Data) |
4 | } |
5 | public protocol ImageProcessor { |
6 | //标识符,在缓存的时候用到,用于区分原始数据和处理加工之后的数据的 |
7 | var identifier: String { get } |
8 | //交给具体的实现类去实现,ImageProcessItem,最终返回一个UIImage |
9 | func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? |
10 | } |
关于 Processor 的两个问题
如果你了解过 Kingfisher,请尝试回答下这 2 个问题
- ImageProcessor.process 都在什么时候调用呢?
- ImageProcessItem 关联了 2 种类型,一种是 Data,另一种是 UIImage,那么这 2 种类型分别什么时候会用到呢?
ImageProcessor.process 在什么时候调用,在调用的时候会传递什么类型的数据?
- 当从网络上下载图片成功之后,会调用 process 把下载成功的 data 加工处理成我们需要的 UIImage。很明显这种情况下传递的是 Data 类型。
- 当 source 是 ImageDataProvider 时,从 source 中获取到 Data 之后,会调用 process 把 data 加工处理成我们需要的 UIImage。很明显这种情况下传递的也是 Data 类型。
- 当读取缓存失败,但读取原始数据缓存成功之后,会调用 process 把原始数据加工处理成我们需要的 UIImage。这种情况会先把读取到的 data 使用 cacheSerializer 反序列化为 UIImage,然后传递 UIImage 类型
CacheSerializer
CacheSerializer 介绍
Kingfisher 中 CacheSerializer 定义了图片序列化和反序列化的能力,也是一个协议
1 | public protocol CacheSerializer { |
2 | func data(with image: KFCrossPlatformImage, original: Data?) -> Data? |
3 | func image(with data: Data, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? |
4 | } |
CacheSerializer 的调用时机
- 当需要磁盘缓存时,会调用
func data(with image: KFCrossPlatformImage, original: Data?) -> Data?把 image 序列化成 data,以便写入文件 - 当从磁盘读取数据时,会调用
func image(with data: Data, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage?把 data 反序列化为 UIImage
使用 Processor 和 CacheSerializer 扩展 Kingfisher,使 Kingfisher 支持 webP 格式的图片
Kingfisher 本身是不支持 webp 格式的图片,但是可以利用 Processor 和 CacheSerializer 对 Kingfisher 进行扩展,让 Kingfisher 支持 webP 格式的图片
WebP 标准是 Google 定制的,迄今为止也只有 Google 发布的 libwebp 实现了该的编解码 。 所以这个库也是该格式的事实标准。
因此要想支持 webp 格式的图片,需要依赖 libwebp 库,用来实现图片的编码和解码,对于这块的代码我是从SDWebImageWebPCoder复制过来的,并且去掉了对动图的支持和一些 SD 配置的代码,如果你对这块感兴趣,请参考源码,由于 SD 是 OC 写的,所以这部分我用的也是 OC,最终给 UIImage 添加了一个分类,提供了下面 2 个方法
1 | @interface UIImage (WebP) |
2 | //序列化为Data |
3 | @property(nonatomic,strong,readonly,nullable) NSData *webPData; |
4 | //通过data反序列化为UIImage |
5 | + (nullable instancetype)imageWithWebPData:(NSData *)webPdata; |
6 | + |
7 | @end |
实现 Processor
在 process 判断 item 的类型,若是 image 则直接返回,若是 data 则反序列化为 UIImage
1 | public struct WebPProcessor: ImageProcessor { |
2 | public static let `default` = WebPProcessor() |
3 | public let identifier = "WebPProcessor" |
4 | public init() {} |
5 | |
6 | public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? { |
7 | switch item { |
8 | case .image(let image): |
9 | return image |
10 | case .data(let data): |
11 | return UIImage(webPData: data) |
12 | } |
13 | } |
14 | } |
CacheSerializer
1 | public struct WebPCacheSerializer: CacheSerializer { |
2 | public static let `default` = WebPCacheSerializer() |
3 | private init() {} |
4 | |
5 | public func data(with image: KFCrossPlatformImage, original: Data?) -> Data? { |
6 | return image.webPData; |
7 | } |
8 | |
9 | public func image(with data: Data, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? { |
10 | return UIImage(webPData: data); |
11 | } |
12 | } |
使用
1 | if let url = URL(string:"http://q21556z4z.bkt.clouddn.com/123.webp?e=1575537931&token=7n8bncOpnUSrN4mijeEAJRdVXnC-jm-mk5qTjKjR:L1_MWy3xugv9ct6PD294CHzwiSE=&attname=") { |
2 | imageView.kf.setImage( |
3 | with: url, |
4 | options: [.processor(WebPProcessor.default), .cacheSerializer(WebPCacheSerializer.default)] |
5 | ) |
6 | } |
补充
虽说上面的代码都比较简单,但是我感觉 Kingfisher 的这个设计真的挺好的,可扩展支持任意类型的图片,并且 Processor 是用来加工处理图片的,能做的还有其他方面,比如 Kingfisher 中提供了多种实现类,比如圆角的 RoundCornerImageProcessor,显示高清图的 DownsamplingImageProcessor,组装多种 Processor 的 GeneralProcessor。
demo 地址