Kingfisher源碼解析之ImagePrefetcher

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

ImagePrefetcher提供了哪些功能

ImagePrefetcher是Kingfisher提供預加載功能的一個類,提供了一下功能數組

  • start():開啓預加載
  • stop():中止預加載
  • maxConcurrentDownloads:設置最大緩存併發量
  • progressBlock和progressSourceBlock:緩存進度的回調
  • completionHandler和completionSourceHandler:緩存結束的回調

ImagePrefetcher預加載的流程圖

ImagePrefetcher預加載的流程圖

ImagePrefetcher兩個問題

當調用stop()函數以後的邏輯

先來看下stop函數的實現,實現比較簡單,在預加載的隊列裏異步的執行把標誌位stopped設置爲true,而且取消當前全部未完成的下載任務,看起來很簡單。緩存

public func stop() {
    pretchQueue.async {
        if self.finished { return }
        self.stopped = true
        self.tasks.values.forEach { $0.cancel() }
    }
}
複製代碼

可是stopped這個標誌位只在網絡請求結束的回調裏去判斷了,這就會發生一些歧義,交給讀者去判斷Kingfisher這麼作是不是合理的?當調用stop函數時,會出現如下幾種狀況以及對應的結果bash

  1. 調用stop時,已經預加載結束了,因爲已經結束,會直接返回
  2. 調用stop時,如今已經有正在下載圖片的任務了,會取消所全部請求,而後請求就會走結束的回調,在結束的回調裏把剩下的未加載的數據放入到失敗的數據源的數組中,調用結束回調
  3. 調用stop時,尚未正在下載的任務,會繼續預加載數據,直到結束,或者有一個請求結束

對於狀況1和狀況2都是合理的,而且是絕大部分都會是狀況1和狀況2,對於狀況3,調用stop時並無真正的去中止,可是這種狀況也是較少出現的。網絡

對於stop方法,喵神的註釋是這樣的併發

/// Stops current downloading progress, and cancel any future prefetching activity that might be occuring.異步

緩存進度和緩存結束的回調爲何要各有2個

我第一次看代碼,就想爲何要有2個呢?爲何這麼設計呢?這裏以緩存進度的回調舉例,它們兩個的緣由是同樣的。先來看下定義,async

public typealias PrefetcherProgressBlock =
    ((_ skippedResources: [Resource], _ failedResources: [Resource], _ completedResources: [Resource]) -> Void)

public typealias PrefetcherSourceProgressBlock =
    ((_ skippedSources: [Source], _ failedSources: [Source], _ completedSources: [Source]) -> Void)
複製代碼

咱們發現基本是同樣的,只是回調裏的參數類型不同,一個Resource,另外一個Source。若是你對這2個類型比較瞭解,想必你應該能猜到這麼設計的緣由了。ide

Source是一個枚舉,Kingfisher中爲UIImage提供數據源用的,定義以下,有2個case,一個是關聯了Resource,另外一個關聯了ImageDataProvider函數

public enum Source {
    case network(Resource)
    case provider(ImageDataProvider)
}
複製代碼

Resource是一個協議,定義以下,提供數據源的真正類型之一,通常用於加載網絡圖片

public protocol Resource {
    var cacheKey: String { get }
    var downloadURL: URL { get }
}
複製代碼

ImageDataProvider也是一個協議,定義以下,提供數據源的另外一個真正類型,通常用於本地圖片

public protocol ImageDataProvider {
    var cacheKey: String { get }
    func data(handler: @escaping (Result<Data, Error>) -> Void)
}
複製代碼

回答上面的問題,因爲咱們通常狀況下預加載的都是網絡圖片,所以提供一個方便咱們使用的回調,但爲了覆蓋到全部狀況,就提供了2個狀況的回調,這個在ImagePrefetcher的便利初始化方法裏咱們就能看出來,當使用[URL](注:在URL的擴展裏實現了Resource協議)或者[Resource]初始化的時候,就使用PrefetcherProgressBlock,當使用[Source]初始化時,就使用的PrefetcherSourceProgressBlock

相關文章
相關標籤/搜索