Kingfisher源碼解析系列,由于水平有限,哪里有錯规辱,肯請不吝賜教
- Kingfisher源碼解析之使用
- Kingfisher源碼解析之Options解釋
- Kingfisher源碼解析之加載流程
- Kingfisher源碼解析之加載動圖
- Kingfisher源碼解析之ImageCache
- Kingfisher源碼解析之Processor和CacheSerializer
- Kingfisher源碼解析之ImagePrefetcher
ImagePrefetcher提供了哪些功能
ImagePrefetcher是Kingfisher提供預(yù)加載功能的一個類赛糟,提供了一下功能
- start():開啟預(yù)加載
- stop():停止預(yù)加載
- maxConcurrentDownloads:設(shè)置最大緩存并發(fā)量
- progressBlock和progressSourceBlock:緩存進度的回調(diào)
- completionHandler和completionSourceHandler:緩存結(jié)束的回調(diào)
ImagePrefetcher預(yù)加載的流程圖
ImagePrefetcher兩個問題
當調(diào)用stop()函數(shù)之后的邏輯
先來看下stop函數(shù)的實現(xiàn),實現(xiàn)比較簡單晒他,在預(yù)加載的隊列里異步的執(zhí)行把標志位stopped設(shè)置為true,并且取消當前所有未完成的下載任務(wù)逸贾,看起來很簡單陨仅。
public func stop() {
pretchQueue.async {
if self.finished { return }
self.stopped = true
self.tasks.values.forEach { $0.cancel() }
}
}
但是stopped這個標志位只在網(wǎng)絡(luò)請求結(jié)束的回調(diào)里去判斷了,這就會發(fā)生一些歧義铝侵,交給讀者去判斷Kingfisher這么做是否是合理的灼伤?當調(diào)用stop函數(shù)時,會出現(xiàn)以下幾種情況以及對應(yīng)的結(jié)果
- 調(diào)用stop時咪鲜,已經(jīng)預(yù)加載結(jié)束了狐赡,由于已經(jīng)結(jié)束,會直接返回
- 調(diào)用stop時疟丙,現(xiàn)在已經(jīng)有正在下載圖片的任務(wù)了颖侄,會取消所所有請求鸟雏,然后請求就會走結(jié)束的回調(diào),在結(jié)束的回調(diào)里把剩下的未加載的數(shù)據(jù)放入到失敗的數(shù)據(jù)源的數(shù)組中览祖,調(diào)用結(jié)束回調(diào)
- 調(diào)用stop時孝鹊,還沒有正在下載的任務(wù),會繼續(xù)預(yù)加載數(shù)據(jù)展蒂,直到結(jié)束又活,或者有一個請求結(jié)束
對于情況1和情況2都是合理的,并且是絕大部分都會是情況1和情況2玄货,對于情況3皇钞,調(diào)用stop時并沒有真正的去停止,但是這種情況也是較少出現(xiàn)的松捉。
對于stop方法夹界,喵神的注釋是這樣的
/// Stops current downloading progress, and cancel any future prefetching activity that might be occuring.
緩存進度和緩存結(jié)束的回調(diào)為什么要各有2個
我第一次看代碼,就想為什么要有2個呢隘世?為什么這么設(shè)計呢可柿?這里以緩存進度的回調(diào)舉例,它們兩個的原因是一樣的丙者。先來看下定義复斥,
public typealias PrefetcherProgressBlock =
((_ skippedResources: [Resource], _ failedResources: [Resource], _ completedResources: [Resource]) -> Void)
public typealias PrefetcherSourceProgressBlock =
((_ skippedSources: [Source], _ failedSources: [Source], _ completedSources: [Source]) -> Void)
我們發(fā)現(xiàn)基本是一樣的,只是回調(diào)里的參數(shù)類型不一樣械媒,一個Resource目锭,另一個Source。如果你對這2個類型比較了解纷捞,想必你應(yīng)該能猜到這么設(shè)計的原因了痢虹。
Source是一個枚舉,Kingfisher中為UIImage提供數(shù)據(jù)源用的主儡,定義如下,有2個case奖唯,一個是關(guān)聯(lián)了Resource,另一個關(guān)聯(lián)了ImageDataProvider
public enum Source {
case network(Resource)
case provider(ImageDataProvider)
}
Resource是一個協(xié)議糜值,定義如下丰捷,提供數(shù)據(jù)源的真正類型之一,一般用于加載網(wǎng)絡(luò)圖片
public protocol Resource {
var cacheKey: String { get }
var downloadURL: URL { get }
}
ImageDataProvider也是一個協(xié)議寂汇,定義如下病往,提供數(shù)據(jù)源的另一個真正類型,一般用于本地圖片
public protocol ImageDataProvider {
var cacheKey: String { get }
func data(handler: @escaping (Result<Data, Error>) -> Void)
}
回答上面的問題骄瓣,由于我們一般情況下預(yù)加載的都是網(wǎng)絡(luò)圖片停巷,因此提供一個方便我們使用的回調(diào),但為了覆蓋到所有情況,就提供了2個情況的回調(diào)叠穆,這個在ImagePrefetcher的便利初始化方法里我們就能看出來,當使用[URL](注:在URL的擴展里實現(xiàn)了Resource協(xié)議)或者[Resource]初始化的時候臼膏,就使用PrefetcherProgressBlock硼被,當使用[Source]初始化時,就使用的PrefetcherSourceProgressBlock