Kingfisher源码阅读(一)

1、前言

Kingfisher Github地址git

Kingfisherswift语言编写的一款很是受欢迎的图片加载库,功能和OC语言编写的SDWebImage相似。做者猫神是我初入iOS开发到如今都很崇拜的偶像。github


2、Kingfisher的通常使用

imageView.kf.setImage(with: imageURL)
复制代码

从上面的使用方法能够看出Kingfisher的使用方法很是简单,那么里面是怎么实现的呢?swift


3、 主要流程

1. Kingfisher.swift文件中

关键点: Kingfisher缓存

不知道你是否对上面使用方法中的kf好奇,我记得我第一次使用的时候,还不是这种写法。下面来揭开它的神秘面纱:ide

public final class Kingfisher<Base> {
    public let base: Base
    public init(_ base: Base) {
        self.base = base
    }
}

public protocol KingfisherCompatible {
    associatedtype CompatibleType
    var kf: CompatibleType { get }
}

public extension KingfisherCompatible {
    public var kf: Kingfisher<Self> {
        get { return Kingfisher(self) }
    }
}

extension ImageView: KingfisherCompatible { }
复制代码

这里的Image是为了适配多款系统而typealias的一个类型别名,在AppKit中为NSImage,UIKit中为UIImage工具

1.先定义了一个不可继承的Kingfisher类,他有一个泛型属性base。动画

2.而后定义了一个KingfisherCompatible协议,定义了一个只读的kf关联类型属性。url

3.在扩展中实现了KingfisherCompatible协议,指定关联类型为Kingfisher<Self>,这里的Self理解为协议约束,须要遵照KingfisherCompatible协议的类型,例如这里的就是Imagespa

4.ImageView遵照KingfisherCompatible协议。线程

而后就可使用了,ImageView+Kingfisher.swift中:

extension Kingfisher where Base: ImageView {
    // 省略
}
复制代码

这里看上去是在给Kingfisher添加扩展,实际上是给ImageView,由于Kingfisher中的base属性其实就是ImageView的实例对象,咱们只须要在添加的方法中用base代替咱们直接给UIImageView添加扩展中的self就好了。

可是目前这种写法有一个限制,那就是结构体没法使用,由于Kingfisher<Self>中的Self是不支持结构体的,若是结构体也想要使用这种方法,那只有单独写,例如String+MD5.swift文件中的:

public struct StringProxy {
    fileprivate let base: String
    init(proxy: String) {
        base = proxy
    }
}

extension String: KingfisherCompatible {
    public typealias CompatibleType = StringProxy
    public var kf: CompatibleType {
        return StringProxy(proxy: self)
    }
}
复制代码

这里和上面相似就不赘述了,咱们本身的写的工具库或者三方也能自定义这样的写法来避免冲突.


2. ImageView+Kingfisher.swift中

关键点: KingfisherOptionsInfo是一个枚举,用来配置库中的信息,例如后台线程解码图片,和出现的动画等等.

这个方法主要配置了一些信息,例如默认图片和加载指示器等等.而后就将获取图片的任务转交给了KingfisherManager。 获取图片成功后,根据配置的显示动画,获取显示并动画显示图片

公开分类方法

public func setImage(with resource: Resource?, placeholder: Placeholder? = nil, options: KingfisherOptionsInfo? = nil, progressBlock: DownloadProgressBlock? = nil, completionHandler: CompletionHandler? = nil) 
                     -> RetrieveImageTask
{
    // 省略 
    // -> 3 KingfisherOptionsInfo配置后等,将任务交给KingfisherManager。
    // 根据配置的动画,获取显示并动画显示图片
}
复制代码

3.KingfisherManager.swift中

关键点: KingfisherManager,用来获取图片和下载缓存图片。

获取图片:

public func retrieveImage(with resource: Resource, options: KingfisherOptionsInfo?, progressBlock: DownloadProgressBlock?, completionHandler: CompletionHandler?) -> RetrieveImageTask
{
    // 省略
    // -> 4.1 若是强制刷新,去下载并缓存
    // -> 4.2 从缓存中获取
}
复制代码

4.1 KingfisherManager.swift中

关键点: ImageDownloader,图片下载器。

关键点: ImageCache,图片缓存器。

关键点: ImageProcessor,图片处理器。

将任务直接交给ImageDownloader,下载成功后用ImageCache来缓存图片,若是有对图片的处理配置,ImageProcessItem还会对图片进行处理。

@discardableResult
func downloadAndCacheImage(with url: URL, forKey key: String, retrieveImageTask: RetrieveImageTask, progressBlock: DownloadProgressBlock?, completionHandler: CompletionHandler?, options: KingfisherOptionsInfo) 
                                -> RetrieveImageDownloadTask?
{
    // 省略
    // -> 5.1 直接将任务交给了ImageDownloader
}
复制代码

4.2 KingfisherManager.swift中

直接将任务交给了ImageCache,尝试从缓存中获取图片

  • 按照配置能获取到图片,直接返回
  • 没有配置图片的处理,而且没有获取到图片,回到4.1从新下载
  • 有配置图片的处理,尝试获取图片的原图,若是有,处理并返回,没有回到4.1从新下载.
func tryToRetrieveImageFromCache(forKey key: String, with url: URL, retrieveImageTask: RetrieveImageTask, progressBlock: DownloadProgressBlock?, completionHandler: CompletionHandler?, options: KingfisherOptionsInfo)
{
    // 省略
    // 5.2 -> 直接将任务交给了ImageCache
}
复制代码

5.1.1 ImageDownloader.swift中

关键点: ImageDownloader,图片下载器

下载图片

downloadImage(with url: URL,
                       retrieveImageTask: RetrieveImageTask? = nil,
                       options: KingfisherOptionsInfo? = nil,
                       progressBlock: ImageDownloaderProgressBlock? = nil,
                       completionHandler: ImageDownloaderCompletionHandler? = nil) 
                       -> RetrieveImageDownloadTask?
{
    // 省略
    // -> 完
}
复制代码

5.1.2 ImageCache.swift中

缓存图片,分为内存缓存和磁盘缓存

open func store(_ image: Image, original: Data? = nil, forKey key: String, processorIdentifier identifier: String = "", cacheSerializer serializer: CacheSerializer = DefaultCacheSerializer.default, toDisk: Bool = true, completionHandler: (() -> Void)? = nil)
{
    // 省略 
    // 内存缓存
    // 磁盘缓存
    // -> 完
}
复制代码

5.2 ImageCache.swift中

根据配置从内存获取或者从磁盘获取获取图片.

@discardableResult
open func retrieveImage(forKey key: String, options: KingfisherOptionsInfo?, completionHandler: ((Image?, CacheType) -> Void)?) 
                        -> RetrieveImageDiskTask?
{
    // 省略 
    // 根据配置从内存获取或者从磁盘获取
}
复制代码

4、后记

这篇这一篇文章主要分析Kingfisher工做的主要流程,细节待后续文章分享。其中还有不少枝叶操做也是颇有意思的。

相关文章
相关标签/搜索