Kingfisher 3.x 學(xué)習(xí)(一)

序言

Kingfisher是喵神的一個(gè)異步下載和緩存圖片的Swift庫,類似于OC 的SDWebImage
中文簡介缀旁,github地址 最近才開始學(xué)習(xí)swift, 所以對于之前的swift 版本不是很了解,直接以最新版本來學(xué)習(xí)了 由于個(gè)人水平有限 如有錯(cuò)誤還望包涵

一、Kingfisher的架構(gòu)

閱讀他人優(yōu)秀代碼是一個(gè)提高自身代碼水平很好的方法鲸湃。花了幾天的時(shí)間子寓,看了Kingfisher的源代碼暗挑,里面包含的很多知識點(diǎn),讓我受益匪淺斜友。3.x版本相比與之前的版本炸裆,一個(gè)重要的改變就是protocol的靈活運(yùn)用,更加面向協(xié)議編程鲜屏。當(dāng)然還有其他很多知識烹看,比如多線程,枚舉洛史,閉包惯殊,Extension 等等應(yīng)用。 Kingfisher中Core也殖,Extension土思,Helpers 三個(gè)目錄結(jié)構(gòu) 共20個(gè)文件

Core
image.swift 文件內(nèi)部對 UIImage 以及 NSData 進(jìn)行了拓展, 包含判定圖片類型、圖片解碼以及Gif數(shù)據(jù)處理等操作
Indicator.swift 圖片加載時(shí)loading指示
ImageCache.swift 主要負(fù)責(zé)將加載過的圖片緩存至本地忆嗜。
ImageDownloader.swift 負(fù)責(zé)下載網(wǎng)絡(luò)圖片己儒。
ImagePrefetcher.swift 可用于提前指定一些圖片下載
ImageProcessor.swift 可用于將下載的數(shù)據(jù)合成圖片對象
CacheSerializer.swift 可用于圖像對象序列化成圖像數(shù)據(jù)存儲到磁盤緩存和從磁盤緩存將圖片數(shù)據(jù)反序列化成圖像對象。
RequestModifier.swift 下載圖像請求修改器捆毫。
ImageTransition.swift 過渡動畫效果 使用UIViewAnimationOptions動畫效果
KingfisherManager.swift Kingfisher 管理控制類闪湾,擁有圖片下載及緩存功能
KingfisherOptionsInfo.swift 枚舉KingfisherOptionsInfoItem 配置 Kingfisher 行為的參數(shù),包括 是否自定義緩存對象 是否自定義下載器 是否過渡動畫 是否設(shè)置下載低優(yōu)先級 是否強(qiáng)制刷新 是否僅獲取緩存圖片 是否僅緩存至內(nèi)存冻璃、是否允許圖像后臺解碼等設(shè)置响谓。
Filter.swift 圖像過濾器
Resource.swift 記錄了圖片的下載地址和緩存Key损合。
Kingfisher.swift 添加KingfisherCompatible通用協(xié)議 kf新屬性

Extension
ImageView+Kingfisher.swift UIButton+Kingfisher.swift NSButton+KingfisherUIImageView UIButton NSButton 進(jìn)行了拓展 主要用于提供 Kingfisher 的外部接口省艳。

Helpers
String+MD5.swift 負(fù)責(zé)圖片緩存時(shí)對文件名進(jìn)行MD5加密操作。
Box.swift 一個(gè)簡單泛型類
ThreadHelper.swift中的 dispatch_async_safely_main_queue 函數(shù)接受一個(gè)閉包 利用 NSThread.isMainThread 判斷并將其放置在主線程中執(zhí)行

二嫁审、Kingfisher.swift

主要文件ImageView+Kingfisher,KingfisherManager,ImageCache,ImageDownloader,廢話不多說直接代碼學(xué)習(xí)

運(yùn)行demo 下面有這么一段代碼:

    let url = URL(string:"https://raw.githubusercontent.com/onevcat/Kingfisher/master/images/kingfisher-\(indexPath.row + 1).jpg")!
    (cell as! CollectionViewCell).cellImageView.kf.setImage(with: url,
                                           placeholder: nil,
                                           options: [.transition(.fade(1))],
                                           progressBlock: { receivedSize, totalSize in
                                            print("\(indexPath.row + 1): \(receivedSize)/\(totalSize)")
            },
                                           completionHandler: { image, error, cacheType, imageURL in
                                            print("\(indexPath.row + 1): Finished")
        })

首先調(diào)用的UIImageViewkf屬性 之前是調(diào)用UIImageViewExtension中的kf_setImage ,現(xiàn)已棄用 那kf 屬性是如何實(shí)現(xiàn)的跋炕?
下面是Kingfisher.swift源碼

  • 自定義了不同平臺下的一些類型別名 swift中的typealias 相當(dāng)于OC中的typedef
#if os(macOS)
    import AppKit
    public typealias Image = NSImage
    public typealias Color = NSColor
    public typealias ImageView = NSImageView
    typealias Button = NSButton
#else
    import UIKit
    public typealias Image = UIImage
    public typealias Color = UIColor
    #if !os(watchOS)
    public typealias ImageView = UIImageView
    typealias Button = UIButton
    #endif
#endif
  • 申明了泛型類Kingfisher 實(shí)現(xiàn)了一個(gè)簡單構(gòu)造器,其中上面的cellImageView就是base屬性
public final class Kingfisher<Base> {
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

  • 申明KingfisherCompatible協(xié)議 有一個(gè)可讀屬性kf 其類型是關(guān)聯(lián)類型
/**
 A type that has Kingfisher extensions.
 */

public protocol KingfisherCompatible {
    associatedtype CompatibleType
    var kf: CompatibleType { get }
}
  • KingfisherCompatible協(xié)議的實(shí)現(xiàn) 屬性kf關(guān)聯(lián)Kingfisher類型 返回一個(gè)Kingfisher實(shí)例 base 參數(shù)就是傳入的self
public extension KingfisherCompatible {
    public var kf: Kingfisher<Self> {
        get { return Kingfisher(self) }
    }
}
  • Image ImageView Button 遵守 KingfisherCompatible 協(xié)議 所以上邊的self參數(shù)就是遵守了協(xié)議的類型 因此base屬性即cellImageView
extension Image: KingfisherCompatible { }
#if !os(watchOS)
extension ImageView: KingfisherCompatible {}
extension Button: KingfisherCompatible { }
#endif

三律适、ImageView+Kingfisher

現(xiàn)在來說說setImage這個(gè)方法的實(shí)現(xiàn) 這個(gè)方法是在Kingfisher的Extension 中實(shí)現(xiàn) 并且要求Base屬于UIImageView類型 即where Base: ImageView 由于kf 屬性關(guān)聯(lián)了Kingfisher
所以可以調(diào)用(cell as! CollectionViewCell).cellImageView.kf.setImage
Extensions目錄下的三個(gè)文件都是類似實(shí)現(xiàn)的 這里就以ImageView+Kingfisher.swift為例
下面方法是外部使用Kingfisher最頻繁也是最重要的方法
第一個(gè)參數(shù)Resource是一個(gè)URL遵守的Protocol辐烂,一般傳入圖片的URL遏插,不可為空
第二個(gè)參數(shù)placeholder是一個(gè)默認(rèn)的占位圖,可為空
第三個(gè)參數(shù)KingfisherOptionsInfo 是個(gè)枚舉數(shù)組纠修,配置Kingfisher下載圖片的一些操作行為
第四個(gè)參數(shù)DownloadProgressBlock是個(gè)下載進(jìn)度閉包胳嘲,可以用于更新下載UI
第五個(gè)參數(shù)completionHandler是個(gè)下載完成閉包,閉包參數(shù)包含圖片扣草,錯(cuò)誤了牛,緩存類型,URL 信息

extension Kingfisher where Base: ImageView {
    /**
     Set an image with a resource, a placeholder image, options, progress handler and completion handler.
     
     - parameter resource:          Resource object contains information such as `cacheKey` and `downloadURL`.
     - parameter placeholder:       A placeholder image when retrieving the image at URL.
     - parameter options:           A dictionary could control some behaviors. See `KingfisherOptionsInfo` for more.
     - parameter progressBlock:     Called when the image downloading progress gets updated.
     - parameter completionHandler: Called when the image retrieved and set.
     
     - returns: A task represents the retrieving process.
     
     - note: Both the `progressBlock` and `completionHandler` will be invoked in main thread.
     The `CallbackDispatchQueue` specified in `optionsInfo` will not be used in callbacks of this method.
     */
    @discardableResult 忽略返回值警告
    public func setImage(with resource: Resource?,
                         placeholder: Image? = nil,
                         options: KingfisherOptionsInfo? = nil,
                         progressBlock: DownloadProgressBlock? = nil,
                         completionHandler: CompletionHandler? = nil) -> RetrieveImageTask
    {
        當(dāng)傳入的resource為空時(shí) 使用guard語句提前退出 Resource是一個(gè)協(xié)議 URL遵守此協(xié)議 Resource有兩個(gè)屬性 cacheKey和downloadURL
        guard let resource = resource else {
            base.image = placeholder
            completionHandler?(nil, nil, .none, nil)
            return .empty
        }
        圖片加載過程中是否顯示placeholder
        var options = options ?? KingfisherEmptyOptionsInfo
        if !options.keepCurrentImageWhileLoading {
            base.image = placeholder
        }
        如果indicator存在辰妙,開啟轉(zhuǎn)圈動畫 indicator 通過屬性關(guān)聯(lián)存取
        let maybeIndicator = indicator
        maybeIndicator?.startAnimatingView()
        關(guān)聯(lián)屬性綁定下載的URL
        setWebURL(resource.downloadURL)

        默認(rèn)開啟加載所有GIF圖片數(shù)據(jù)鹰祸,顯示GIF 動態(tài)圖片
        if base.shouldPreloadAllGIF() {
            options.append(.preloadAllGIFData)
        }
        調(diào)用KingfisherManager的方法來獲取圖片
        let task = KingfisherManager.shared.retrieveImage(
            with: resource,
            options: options,
            progressBlock: { receivedSize, totalSize in
                下載進(jìn)度回調(diào)
                if let progressBlock = progressBlock {
                    progressBlock(receivedSize, totalSize)
                }
            },
            completionHandler: {[weak base] image, error, cacheType, imageURL in
                確保線程安全
                DispatchQueue.main.safeAsync {
                    確保返回的圖片與URL對應(yīng)一致
                    guard let strongBase = base, imageURL == self.webURL else {
                        return
                    }
                    self.setImageTask(nil)
                    沒有圖片返回停止動畫返回錯(cuò)誤
                    guard let image = image else {
                        maybeIndicator?.stopAnimatingView()
                        completionHandler?(nil, error, cacheType, imageURL)
                        return
                    }
                    是否需要過渡動畫 transitionItem 為 options中第一個(gè).transition
                    需要過渡動畫需要滿足以下情況
                    1.transitionItem存在且不為.transition(.none)
                    2.options.forceTransition存在 或者 cacheType == .none 
                    guard let transitionItem = options.firstMatchIgnoringAssociatedValue(.transition(.none)),
                        case .transition(let transition) = transitionItem, ( options.forceTransition || cacheType == .none) else
                    {
                        maybeIndicator?.stopAnimatingView()
                        strongBase.image = image
                        completionHandler?(image, error, cacheType, imageURL)
                        return
                    }
                    過渡動畫
                    #if !os(macOS)
                        UIView.transition(with: strongBase, duration: 0.0, options: [],
                                          animations: { maybeIndicator?.stopAnimatingView() },
                                          completion: { _ in
                                            UIView.transition(with: strongBase, duration: transition.duration,
                                                              options: [transition.animationOptions, .allowUserInteraction],
                                                              animations: {
                                                                // Set image property in the animation.
                                                                設(shè)置圖片,如果是自定義動畫 在定義動畫回調(diào)中設(shè)置圖片密浑,代碼在ImageTransition.swift
                                                                transition.animations?(strongBase, image)
                                                              },
                                                              completion: { finished in
                                                                動畫結(jié)束回調(diào)
                                                                transition.completion?(finished)
                                                                completionHandler?(image, error, cacheType, imageURL)
                                                              })
                                          })
                    #endif
                }
            })
        setImageTask(task)
   return task
    }
    /**
     Cancel the image download task bounded to the image view if it is running.
     Nothing will happen if the downloading has already finished.
     */
    取消下載
    public func cancelDownloadTask() {
        imageTask?.downloadTask?.cancel()
    }
}

ImageView+Kingfisher 中的WebUR indicatorType indicator imageTask 屬性均使用屬性關(guān)聯(lián)技術(shù)實(shí)現(xiàn)數(shù)據(jù)的存取

四 蛙婴、KingfisherManager

該類是Kingfisher唯一的一個(gè)管理調(diào)度類。這個(gè)類有下載和緩存兩大功能模塊 主要包含了兩個(gè)屬性 兩個(gè)方法
public var cache: ImageCache 圖片緩存屬性
public var downloader: ImageDownloader 圖片下載屬性
func downloadAndCacheImage 下載并且緩存圖片方法
func tryToRetrieveImageFromCache 獲取緩存圖片

ImageView+Kingfisher中最后圖片的獲取就是由KingfisherManager的單例實(shí)現(xiàn)的retrieveImage

  • 外部調(diào)用獲取圖片方法
func retrieveImage(with resource: Resource,
        options: KingfisherOptionsInfo?,
        progressBlock: DownloadProgressBlock?,
        completionHandler: CompletionHandler?) -> RetrieveImageTask{
        let task = RetrieveImageTask()
        if let options = options, options.forceRefresh {
             強(qiáng)制刷新 從網(wǎng)絡(luò)獲取圖片
            _ = downloadAndCacheImage(
                with: resource.downloadURL,
                forKey: resource.cacheKey,
                retrieveImageTask: task,
                progressBlock: progressBlock,
                completionHandler: completionHandler,
                options: options)
        } else {
            從緩存獲取圖片
            tryToRetrieveImageFromCache(
                forKey: resource.cacheKey,
                with: resource.downloadURL,
                retrieveImageTask: task,
                progressBlock: progressBlock,
                completionHandler: completionHandler,
                options: options)
        }
        return task
    }
  • 下載并且緩存圖片的方法
   func downloadAndCacheImage(with url: URL,
                             forKey key: String,
                      retrieveImageTask: RetrieveImageTask,
                          progressBlock: DownloadProgressBlock?,
                      completionHandler: CompletionHandler?,
                                options: KingfisherOptionsInfo?) -> RetrieveImageDownloadTask?
    {
        獲取下載器 并開啟下載 
        let options = options ?? KingfisherEmptyOptionsInfo
        let downloader = options.downloader
        return downloader.downloadImage(with: url, retrieveImageTask: retrieveImageTask, options: options,
            progressBlock: { receivedSize, totalSize in
                progressBlock?(receivedSize, totalSize)
            },
            completionHandler: { image, error, imageURL, originalData in

                let targetCache = options.targetCache
                if let error = error, error.code == KingfisherError.notModified.rawValue {
                    // Not modified. Try to find the image from cache.
                    // (The image should be in cache. It should be guaranteed by the framework users.)
                   如果有錯(cuò)誤并且沒有修改過URL 返回緩存圖片
                    targetCache.retrieveImage(forKey: key, options: options, completionHandler: { (cacheImage, cacheType) -> () in
                        completionHandler?(cacheImage, nil, cacheType, url)
                    })
                    return
                }
                緩存圖片 
                if let image = image, let originalData = originalData {
                    targetCache.store(image,
                                      original: originalData,
                                      forKey: key,
                                      processorIdentifier:options.processor.identifier,
                                      cacheSerializer: options.cacheSerializer,
                                      toDisk: !options.cacheMemoryOnly,
                                      completionHandler: nil)
                }

                completionHandler?(image, error, .none, url)

            })
    }
  • 優(yōu)先從緩存獲取圖片尔破,如緩存中沒有街图,在從網(wǎng)絡(luò)獲取圖片
    func tryToRetrieveImageFromCache(forKey key: String,
                                       with url: URL,
                              retrieveImageTask: RetrieveImageTask,
                                  progressBlock: DownloadProgressBlock?,
                              completionHandler: CompletionHandler?,
                                        options: KingfisherOptionsInfo?)
    {
        打破下面diskTask內(nèi)部閉包保持的循環(huán)引用,完成之后取消磁盤任務(wù)引用懒构,避免循環(huán)引用台夺,釋放內(nèi)存
        let diskTaskCompletionHandler: CompletionHandler = { (image, error, cacheType, imageURL) -> () in
            // Break retain cycle created inside diskTask closure below
            retrieveImageTask.diskRetrieveTask = nil
            completionHandler?(image, error, cacheType, imageURL)
        }
        
        let targetCache = options?.targetCache ?? cache
        let diskTask = targetCache.retrieveImage(forKey: key, options: options,
            completionHandler: { image, cacheType in
                if image != nil {
                     成功返回圖片
                    diskTaskCompletionHandler(image, nil, cacheType, url)
                } else if let options = options, options.onlyFromCache {
                    返回失敗 并且設(shè)置只從緩存獲取圖片 返回沒有緩存錯(cuò)誤
                    let error = NSError(domain: KingfisherErrorDomain, code: KingfisherError.notCached.rawValue, userInfo: nil)
                    diskTaskCompletionHandler(nil, error, .none, url)
                } else {
                    返回失敗 再從網(wǎng)絡(luò)下載圖片
                    self.downloadAndCacheImage(
                        with: url,
                        forKey: key,
                        retrieveImageTask: retrieveImageTask,
                        progressBlock: progressBlock,
                        completionHandler: diskTaskCompletionHandler,
                        options: options)
                }
            }
        )
        retrieveImageTask.diskRetrieveTask = diskTask
    }

五、 KingfisherOptionsInfo

上面代碼多次用到options這個(gè)參數(shù)痴脾,它的參數(shù)類型是KingfisherOptionsInfo是一個(gè)類型別名
public typealias KingfisherOptionsInfo = [KingfisherOptionsInfoItem]
KingfisherOptionsInfoItem 是一個(gè)枚舉 配置 Kingfisher所有功能行為 下面是詳細(xì)中文注釋

public enum KingfisherOptionsInfoItem {

    這個(gè)成員的關(guān)聯(lián)值是一個(gè)ImageCache對象颤介。 Kingfisher使用指定的緩存對象處理 相關(guān)業(yè)務(wù),包括試圖檢索緩存圖像和存儲下載的圖片。
    case targetCache(ImageCache)

    這個(gè)成員的關(guān)聯(lián)值應(yīng)該是一個(gè)ImageDownloader對象赞赖。Kingfisher將使用這個(gè)下載器下載的圖片滚朵。
    case downloader(ImageDownloader)

    如果從網(wǎng)絡(luò)下載的圖片 Kingfisher將使用“ImageTransition這個(gè)枚舉動畫。從內(nèi)存或磁盤緩存時(shí)默認(rèn)過渡不會發(fā)生前域。如果需要,設(shè)置ForceTransition
    case transition(ImageTransition)

    有關(guān)“浮動”值將被設(shè)置為圖像下載任務(wù)的優(yōu)先級辕近。值在0.0 ~ 1.0之間。如果沒有設(shè)置這個(gè)選項(xiàng),默認(rèn)值(“NSURLSessionTaskPriorityDefault”)將被使用匿垄。
    case downloadPriority(Float)

    如果設(shè)置,將忽略緩存,開啟一個(gè)下載任務(wù)的資源
    case forceRefresh
    
    如果設(shè)置 即使緩存的圖片也將開啟過渡動畫
    case forceTransition

    如果設(shè)置移宅,Kingfisher只會在內(nèi)存中緩存值而不是磁盤
    case cacheMemoryOnly

    如果設(shè)置 Kingfisher只會從緩存中加載圖片
    case onlyFromCache
    
    在使用之前在后臺線程解碼圖像
    case backgroundDecode
    
    當(dāng)從緩存檢索圖像時(shí) 這個(gè)成員的關(guān)聯(lián)值將被用作目標(biāo)隊(duì)列的調(diào)度時(shí)回調(diào)。如果沒 有設(shè)置, Kingfisher將使用主要quese回調(diào)
    case callbackDispatchQueue(DispatchQueue?)
    
    將檢索到的圖片數(shù)據(jù)轉(zhuǎn)換成一個(gè)圖時(shí) 這個(gè)成員變量將被用作圖片縮放因子椿疗。圖像分辨率,而不是屏幕尺寸漏峰。你可能處理時(shí)需要指定正確的縮放因子@2x或@3x Retina圖像。
    case scaleFactor(CGFloat)
    
    是否所有的GIF應(yīng)該加載數(shù)據(jù)届榄。默認(rèn)false浅乔,只顯示GIF中第一張圖片。如果true,所有的GIF數(shù)據(jù)將被加載到內(nèi)存中進(jìn)行解碼。這個(gè)選項(xiàng)主要是用于內(nèi)部的兼容性靖苇。你不應(yīng)該把直接設(shè)置它席噩。“AnimatedImageView”不會預(yù)加載所有數(shù)據(jù),而一個(gè)正常的圖像視圖(“UIImageView”或“NSImageView”)將加載所有數(shù)據(jù)贤壁。選擇使用相應(yīng)的圖像視圖類型而不是設(shè)置這個(gè)選項(xiàng)悼枢。
    case preloadAllGIFData
  
    發(fā)送請求之前用于改變請求。這是最后的機(jī)會你可以修改請求脾拆。您可以修改請求一些定制的目的,如添加身份驗(yàn)證令牌頭,進(jìn)行基本的HTTP身份驗(yàn)證或類似的url映射萧芙。原始請求默認(rèn)情況下將沒有任何修改
    case requestModifier(ImageDownloadRequestModifier)
    
    下載完成時(shí),處理器會將下載的數(shù)據(jù)轉(zhuǎn)換為一個(gè)圖像。如果緩存連接到下載器(當(dāng)你正在使用KingfisherManager或圖像擴(kuò)展方法),轉(zhuǎn)換后的圖像也將被緩存
    case processor(ImageProcessor)
    
    提供一個(gè)CacheSerializer 可用于圖像對象序列化成圖像數(shù)據(jù)存儲到磁盤緩存和從磁盤緩存將圖片數(shù)據(jù)反序列化成圖像對象
    case cacheSerializer(CacheSerializer)
    
    保持現(xiàn)有的圖像同時(shí)設(shè)置另一個(gè)圖像圖像視圖假丧。通過設(shè)置這個(gè)選項(xiàng),imageview的placeholder參數(shù)將被忽略和當(dāng)前圖像保持同時(shí)加載新圖片
    case keepCurrentImageWhileLoading
}

下面是自定義<== 運(yùn)算符 比較兩個(gè)KingfisherOptionsInfoItem 是否相等 相等返回true 否則返回false

precedencegroup ItemComparisonPrecedence {
    associativity: none
    higherThan: LogicalConjunctionPrecedence
}

infix operator <== : ItemComparisonPrecedence

// This operator returns true if two `KingfisherOptionsInfoItem` enum is the same, without considering the associated values.
func <== (lhs: KingfisherOptionsInfoItem, rhs: KingfisherOptionsInfoItem) -> Bool {
    switch (lhs, rhs) {
    case (.targetCache(_), .targetCache(_)): return true
    case (.downloader(_), .downloader(_)): return true
    case (.transition(_), .transition(_)): return true
    case (.downloadPriority(_), .downloadPriority(_)): return true
    case (.forceRefresh, .forceRefresh): return true
    case (.forceTransition, .forceTransition): return true
    case (.cacheMemoryOnly, .cacheMemoryOnly): return true
    case (.onlyFromCache, .onlyFromCache): return true
    case (.backgroundDecode, .backgroundDecode): return true
    case (.callbackDispatchQueue(_), .callbackDispatchQueue(_)): return true
    case (.scaleFactor(_), .scaleFactor(_)): return true
    case (.preloadAllGIFData, .preloadAllGIFData): return true
    case (.requestModifier(_), .requestModifier(_)): return true
    case (.processor(_), .processor(_)): return true
    case (.cacheSerializer(_), .cacheSerializer(_)): return true
    case (.keepCurrentImageWhileLoading, .keepCurrentImageWhileLoading): return true
    default: return false
    }
}

下面是對CollectionType的一個(gè)擴(kuò)展 返回匹配的第一個(gè)相同枚舉值 上面過渡動畫就有用到

public extension Collection where Iterator.Element == KingfisherOptionsInfoItem {
    func firstMatchIgnoringAssociatedValue(_ target: Iterator.Element) -> Iterator.Element? {
        return index { $0 <== target }.flatMap { self[$0] }
    }
    
    func removeAllMatchesIgnoringAssociatedValue(_ target: Iterator.Element) -> [Iterator.Element] {
        return self.filter { !($0 <== target) }
    }
}

KingfisherOptionsInfo中有很多的類似的屬性get方法 如下是關(guān)于圖片編碼的双揪,默認(rèn)返回DefaultCacheSerializer.default。如果要自定義圖片編碼包帚,可以添加自定義CacheSerializerOptions數(shù)組

   public var cacheSerializer: CacheSerializer {
        if let item = firstMatchIgnoringAssociatedValue(.cacheSerializer(DefaultCacheSerializer.default)),
            case .cacheSerializer(let cacheSerializer) = item
        {
            return cacheSerializer
        }
        return DefaultCacheSerializer.default
    }

結(jié)束

至此 渔期,我們對Kingfisher對整體架構(gòu)已經(jīng)有比較清晰的認(rèn)識了 如下圖所示

Kingfisher.png

由于源代碼比較多,一些注釋都寫在代碼部分渴邦,可能看起來有點(diǎn)怪 用簡書也有段時(shí)間疯趟,但這還是第一次自己寫文章 接下來我會繼續(xù)學(xué)習(xí)下載模塊和緩存模塊的過程等等 如有錯(cuò)誤,希望大家不吝指正

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谋梭,一起剝皮案震驚了整個(gè)濱河市信峻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瓮床,老刑警劉巖盹舞,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異隘庄,居然都是意外死亡踢步,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門丑掺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來获印,“玉大人,你說我怎么就攤上這事街州〖娣幔” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵唆缴,是天一觀的道長鳍征。 經(jīng)常有香客問我,道長琐谤,這世上最難降的妖魔是什么蟆技? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任玩敏,我火速辦了婚禮斗忌,結(jié)果婚禮上质礼,老公的妹妹穿的比我還像新娘。我一直安慰自己织阳,他們只是感情好眶蕉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唧躲,像睡著了一般造挽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弄痹,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天饭入,我揣著相機(jī)與錄音,去河邊找鬼肛真。 笑死谐丢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚓让。 我是一名探鬼主播乾忱,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼历极!你這毒婦竟也來了窄瘟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤趟卸,失蹤者是張志新(化名)和其女友劉穎蹄葱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锄列,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡新蟆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了右蕊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片琼稻。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖饶囚,靈堂內(nèi)的尸體忽然破棺而出帕翻,到底是詐尸還是另有隱情,我是刑警寧澤萝风,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布嘀掸,位于F島的核電站,受9級特大地震影響规惰,放射性物質(zhì)發(fā)生泄漏睬塌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望揩晴。 院中可真熱鬧勋陪,春花似錦、人聲如沸硫兰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽劫映。三九已至违孝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泳赋,已是汗流浹背雌桑。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祖今,地道東北人筹燕。 一個(gè)月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像衅鹿,于是被迫代替她去往敵國和親撒踪。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容