
Kingfisher
部分收獲:
- Kingfisher的 kf 寫法
同樣是鏈式編程, 在SnapKit中,view.snp是通過對View進行擴展實現的
類似snp的寫法:
public var snp: ConstraintViewDSL {
return ConstraintViewDSL(view: self)
}
這種寫法來為類添加一個不存在的屬性, snp
但是在 Kingfisher中,onev 是使用了泛型結合協議來做這個事情的.
/**
A type that has Kingfisher extensions.
*/
public protocol KingfisherCompatible {
associatedtype CompatibleType
var kf: CompatibleType { get }
}
public extension KingfisherCompatible {
public var kf: Kingfisher<Self> {
return Kingfisher(self)
}
}
extension ImageView: KingfisherCompatible { }
extension Image: KingfisherCompatible { }
給ImageView和image遵守了一個協議 KingfisherCompatible
從而實現了
imageView.kf 就等同于 let kf: Kingfisher = Kingfisher<imageView>
- 讀寫權限不同
fileprivate(set)
/// It will be `nil` if `indicatorType` is `.none`.
public fileprivate(set) var indicator: Indicator? {
get {
...
}
set {
...
}
}
- Swift5 支持的Result
func cacheImage(_ result: Result<ImageLoadingResult, KingfisherError>)
{
switch result {
case .success(let value):
handle(value)
case .failure(let error):
handle(error)
}
}
value是ImageLoadingResult, error是KingfisherError
- 禁止網絡請求的緩存
4.1. cachePolicy
URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: downloadTimeout)
4.2 URLSessionConfiguration.ephemeral
為了防止網絡請求在我們不知道的情況下被緩存,可以使用ephmeral來進行請求
URLSession是一個可以響應發(fā)送或者接受HTTP請求的關鍵類,可以通過URLSessionConfiguration類新建URLSession實例。有以下三種方式:
URLSessionConfiguration.default
默認configuration實例創(chuàng)建方式,使用硬盤上持久化全局緩存、證書(credential)和cookie的存儲對象
URLSessionConfiguration.ephemeral
唯一跟默認configuration不一樣的是所以與會話(session)相關的數據都存儲在內存中
URLSessionConfiguration.background(withIdentifier: "ConfigurationID")
讓會話在后臺執(zhí)行上載或下載任務。即使應用程序本身被暫停或終止,傳輸仍將繼續(xù)
來說說Kingfisher簡單使用
let url = URL(string: imageURL)
imageView.kf.setImage(with: url)
kf 定義
先看 kf 的定義,返回一個包含自己的 KingfisherWrapper 對象,可以調用 Setting Image 一系列函數。
extension ImageView: KingfisherCompatible { }
extension KingfisherCompatible {
/// Gets a namespace holder for Kingfisher compatible types.
public var kf: KingfisherWrapper<Self> {
get { return KingfisherWrapper(self) }
set { }
}
}
public struct KingfisherWrapper<Base> {
public let base: Base
public init(_ base: Base) {
self.base = base
}
}
設置方法
@discardableResult
public func setImage(
with resource: Resource?,
placeholder: Placeholder? = nil,
options: KingfisherOptionsInfo? = nil,
progressBlock: DownloadProgressBlock? = nil,
completionHandler: ((Result<RetrieveImageResult, KingfisherError>) -> Void)? = nil) -> DownloadTask?
{
return setImage(
with: resource.map { .network($0) },
placeholder: placeholder,
options: options,
progressBlock: progressBlock,
completionHandler: completionHandler)
}
@discardableResult:表示取消不使用返回值的警告
可以看到 setImage(with: url) 內部調用了另外一個相似函數,只不過 source 參數類型從 Resource? 變成 Source? ,我們來看下這兩者的區(qū)別:
public protocol Resource {
var cacheKey: String { get }
var downloadURL: URL { get }
}
public enum Source {
public enum Identifier {
public typealias Value = UInt
static var current: Value = 0
static func next() -> Value {
current += 1
return current
}
}
case network(Resource)
case provider(ImageDataProvider)
public var cacheKey: String {
switch self {
case .network(let resource): return resource.cacheKey
case .provider(let provider): return provider.cacheKey
}
}
public var url: URL? {
switch self {
case .network(let resource): return resource.downloadURL
case .provider(_): return nil
}
}
}
Resource 是協議,Resource 標志這圖片來自網絡,提供cacheKey : String,downloadURL:URL。URL實現該協議,將absoluteString作為緩存的Key。
Source 是枚舉,Source 有兩種類型:.network(Resource) 和 .provider(ImageDataProvider)
imageView.kf.setImage(with: url) 可以直接傳入 url,是因為 URL 實現了 Resource 協議
extension URL: Resource {
public var cacheKey: String { return absoluteString }
public var downloadURL: URL { return self }
}
ImageDataProvider
ImageDataProvider是一個協議,標志這圖片來自網絡,提供cacheKey : String,func data() 來緩存與生成Image。
KingFisher提供了三種默認的Provider:
LocalFileImageDataProvider, 從本地file中讀取Image
Base64ImageDataProvider,從Base64中讀取Image
RawImageDataProvider, 從Data中讀取Image
Placeholder
Placeholder 也是一個協議,提供在ImageView上添加自身和移除自身的功能函數:
func add(to imageView: ImageView)
func remove(from imageView: ImageView)
Image和View有默認的配置:
extension Placeholder where Self: Image
extension Placeholder where Self: View
Image的默認方法是設置imageView的image為自身
View的默認方法是添加覆蓋imageView的子View
KingfisherOptionsInfo
public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem]
/**
Items could be added into KingfisherOptionsInfo.
*/
public enum KingfisherOptionsInfoItem {
case targetCache(ImageCache) //設置緩存器,Kingfisher用這個緩存器來緩存展示的圖片
case originalCache(ImageCache) //設置緩存器,Kingfisher用這個緩存器來緩存下載的原始圖片
case downloader(ImageDownloader) //設置下載器,Kingfisher用這個下載器來下載數據
case transition(ImageTransition) //設置下載完成之后的動畫
case downloadPriority(Float) //0.0~1.0 設置下載優(yōu)先級
case forceRefresh //忽視緩存
case fromMemoryCacheOrRefresh //先嘗試從內存緩存讀取,如果沒有,則重新下載,不會讀取磁盤緩存
case forceTransition //從緩存讀取的圖片也會進行動畫處理
case cacheMemoryOnly //只通過內存緩存圖片
case waitForCache //緩存完成之后才調用completion block
case onlyFromCache //只通過緩存讀取圖片,不會下載
case backgroundDecode //使用圖片前線在后臺線程上解碼
case callbackDispatchQueue(DispatchQueue?) //設置回調在那個隊列上
case scaleFactor(CGFloat) // data轉成Image時的Scale
.....
}
KingfisherManager
KingfisherManager主要由兩部分組成,ImageDownloader用于管理下載;ImageCache用于管理緩存。其主要函數即為:
func retrieveImage(
with source: Source,
options: KingfisherParsedOptionsInfo,
completionHandler: ((Result<RetrieveImageResult, KingfisherError>) -> Void)?) -> DownloadTask?
閱讀源碼之后,我們可以發(fā)現函數loadAndCacheImage負責下載及緩存圖片,函數retrieveImageFromCache負責讀出cache中的圖片。
圖片下載
ImageDownloader
下載圖片的代碼如下:
let downloader = options.downloader ?? ImageDownloader.default
guard let task = downloader.downloadImage(
with: resource.downloadURL,
options: options,
completionHandler: cacheImage) else {
return nil
}
return .download(task)
ImageDownloader
網絡請求的抽象:
private let sessionDelegate: SessionDelegate
private var session: URLSession
open var sessionConfiguration = URLSessionConfiguration.ephemeral {
didSet {
session.invalidateAndCancel()
session = URLSession(configuration: sessionConfiguration, delegate: sessionDelegate, delegateQueue: nil)
}
}
// 自定義證書的驗證邏輯
// https://www.cnblogs.com/Code-life/p/7806824.html
open weak var authenticationChallengeResponder: AuthenticationChallengeResponsable?
這里放一個Kingfisher讀取圖片緩存的邏輯圖.
