Kingfisher源碼解析之Processor和CacheSerializer

Kingfisher源碼解析系列,因爲水平有限,哪裏有錯,肯請不吝賜教git

本篇文章主要介紹Processor和CacheSerializer的基本定義和調用時機,以及利用兩者擴展Kingfisher以支持webp格式的圖片github

Processor

Processor介紹

Kingfisher中Processor是一個協議,定義了對原始數據進行加工處理轉換成UIImage的能力(Kingfisher緩存的是處理成功以後的UIImage,根據options的值來決定是否緩存原始數據)。 這裏的原始數據是指ImageProcessItem,它是一個枚舉類型。Processor和ImageProcessItem定義以下,都是特別簡單web

public enum ImageProcessItem {
    case image(KFCrossPlatformImage)
    case data(Data)
}
public protocol ImageProcessor {
    //標識符,在緩存的時候用到,用於區分原始數據和處理加工以後的數據的
    var identifier: String { get }
    //交給具體的實現類去實現,ImageProcessItem,最終返回一個UIImage
    func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage?
}
複製代碼
關於Processor的兩個問題

若是你瞭解過Kingfisher,請嘗試回答下這2個問題緩存

  1. ImageProcessor.process都在何時調用呢?
  2. ImageProcessItem關聯了2種類型,一種是Data,另外一種是UIImage,那麼這2種類型分別何時會用到呢?

ImageProcessor.process在何時調用,在調用的時候會傳遞什麼類型的數據?bash

  1. 當從網絡上下載圖片成功以後,會調用process把下載成功的data加工處理成咱們須要的UIImage。很明顯這種狀況下傳遞的是Data類型。
  2. 當source是ImageDataProvider時,從source中獲取到Data以後,會調用process把data加工處理成咱們須要的UIImage。很明顯這種狀況下傳遞的也是Data類型。
  3. 當讀取緩存失敗,但讀取原始數據緩存成功以後,會調用process把原始數據加工處理成咱們須要的UIImage。這種狀況會先把讀取到的data使用cacheSerializer反序列化爲UIImage,而後傳遞UIImage類型

CacheSerializer

CacheSerializer介紹

Kingfisher中CacheSerializer定義了圖片序列化和反序列化的能力,也是一個協議網絡

public protocol CacheSerializer {
    func data(with image: KFCrossPlatformImage, original: Data?) -> Data?
    func image(with data: Data, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage?
}
複製代碼
CacheSerializer的調用時機
  1. 當須要磁盤緩存時,會調用func data(with image: KFCrossPlatformImage, original: Data?) -> Data?把image序列化成data,以便寫入文件
  2. 當從磁盤讀取數據時,會調用func image(with data: Data, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage?把data反序列化爲UIImage

使用Processor和CacheSerializer擴展Kingfisher,使Kingfisher支持webP格式的圖片

Kingfisher自己是不支持webp格式的圖片,可是能夠利用Processor和CacheSerializer對Kingfisher進行擴展,讓Kingfisher支持webP格式的圖片ide

WebP 標準是 Google 定製的,迄今爲止也只有 Google 發佈的 libwebp 實現了該的編解碼 。 因此這個庫也是該格式的事實標準。post

所以要想支持webp格式的圖片,須要依賴libwebp庫,用來實現圖片的編碼和解碼,對於這塊的代碼我是從SDWebImageWebPCoder複製過來的,而且去掉了對動圖的支持和一些SD配置的代碼,若是你對這塊感興趣,請參考源碼,因爲SD是OC寫的,因此這部分我用的也是OC,最終給UIImage添加了一個分類,提供了下面2個方法fetch

@interface UIImage (WebP)
//序列化爲Data
@property(nonatomic,strong,readonly,nullable) NSData *webPData;
//經過data反序列化爲UIImage
+ (nullable instancetype)imageWithWebPData:(NSData *)webPdata;
+ 
@end
複製代碼
實現Processor

在process判斷item的類型,如果image則直接返回,如果data則反序列化爲UIImageui

public struct WebPProcessor: ImageProcessor {
    public static let `default` = WebPProcessor()
    public let identifier = "WebPProcessor"
    public init() {}
    
    public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
        switch item {
        case .image(let image):
            return image
        case .data(let data):
            return UIImage(webPData: data)
        }
    }
}
複製代碼
CacheSerializer
public struct WebPCacheSerializer: CacheSerializer {
    public static let `default` = WebPCacheSerializer()
    private init() {}
    
    public func data(with image: KFCrossPlatformImage, original: Data?) -> Data? {
        return image.webPData;
    }
    
    public func image(with data: Data, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
        return UIImage(webPData: data);
    }
}
複製代碼
使用
if let url = URL(string:"http://q21556z4z.bkt.clouddn.com/123.webp?e=1575537931&token=7n8bncOpnUSrN4mijeEAJRdVXnC-jm-mk5qTjKjR:L1_MWy3xugv9ct6PD294CHzwiSE=&attname=") {
    imageView.kf.setImage(
        with: url,
        options: [.processor(WebPProcessor.default), .cacheSerializer(WebPCacheSerializer.default)]
    )
}
複製代碼

補充

雖然說上面的代碼都比較簡單,可是我感受Kingfisher的這個設計真的挺好的,可擴展支持任意類型的圖片,而且Processor是用來加工處理圖片的,能作的還有其餘方面,好比Kingfisher中提供了多種實現類,好比圓角的RoundCornerImageProcessor,顯示高清圖的DownsamplingImageProcessor,組裝多種Processor的GeneralProcessor。 demo地址

參考

SDWebImageWebPCoder
移動端圖片格式調研
libwebp地址

相關文章
相關標籤/搜索