前语

在源码解析的第一篇中,咱们讲解了 Kingfisher 的最主要的功能-异步加载网络图片的流程,以及怎么设计支撑同一个类型参数能够依据 URL 类型加载本地以及网络的资源。

第二篇中,咱们讲解了它怎么完成内存、磁盘双缓存以及缓存的详细配置参数。

这一篇咱们接着来依据 Features 继续整理代码。

Cancelable downloading and auto-reusing previous downloaded content to improve performance.

当咱们加载列表中的图片时,能够在 UITableView 或许 UICollectionView 的署理办法中直接对 cellimageView 直接调用 setImage() 来异步加载网络资源。下面以 UICollectionView 为例子,写一下示例代码:

override func collectionView(
        _ collectionView: UICollectionView,
        cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(
        withReuseIdentifier: "collectionViewCell",
        for: indexPath) as! ImageCollectionViewCell
    let url = ImageLoader.sampleImageURLs[indexPath.row]
    cell.cellImageView.kf.setImage(with: url)
    return cell
}

这样是完全能够完成咱们的需求的。但它也存在一个问题,那就是当你快速滑动的时候,当时屏幕加载的图片可能还未加载完就已经滑出屏幕了。也就是说你消耗的系统资源并不是百分百有用的,由于屏幕外的图片加载你也在执行,但这部分对用户来讲是无效的。咱们能够结合 Kingfisher 的撤销下载和预加载的功能来解决这个问题。

对应 UICollectionView 来说,咱们能够在 didEndDisplaying 的署理办法中撤销下载,在 willDisplay 的署理办法中预加载。示例代码如下:

override func collectionView(
        _ collectionView: UICollectionView,
        didEndDisplaying cell: UICollectionViewCell,
        forItemAt indexPath: IndexPath) {
    (cell as! ImageCollectionViewCell).cellImageView.kf.cancelDownloadTask()
}
override func collectionView(
    _ collectionView: UICollectionView,
    willDisplay cell: UICollectionViewCell,
    forItemAt indexPath: IndexPath) {
    let imageView = (cell as! ImageCollectionViewCell).cellImageView!
    let url = ImageLoader.sampleImageURLs[indexPath.row]
    KF.url(url).set(to: imageView)
}

Independent components. Use the downloader, caching system, and image processors separately as you need.

源码阅览系列之图片加载结构:Kingfisher (第三篇)
通过项目源码的文件分层咱们也能够看出来,Kingfisher 的模块设计做的是非常好的。它的资源加载、缓存或许图片处理器都是能够独自运用的。不一定非得全套运用。

比方,在自己的项目中,经常会碰到一些数据缓存的功能。这时,你就能够独自运用它的缓存功能来完成,这样就不用自己再写一套缓存机制了。示例代码如下(以 String 为例):

extension String: CacheCostCalculable {
    public var cacheCost: Int {
        return Data(self.utf8).count
    }
}
let totalMemory = ProcessInfo.processInfo.physicalMemory
let costLimit = totalMemory / 4
let memoryStorage = MemoryStorage.Backend<String>(config:
    .init(totalCostLimit: (costLimit > Int.max) ? Int.max : Int(costLimit)))
memoryStorage.store(value: "测试数据", forKey: "test_key")

由于它要求存入的值遵守 CacheCostCalculable 协议以核算缓存的巨细,所以咱们需要给 String 的扩展中完成一下 cacheCost 核算特点。

之后的运用代码能够看出来,跟别的模块是没有什么耦合的。

Prefetching images and showing them from the cache to boost your app.

这一条跟上面的预加载是一个意思。

Extensions forUIImageView,NSImageView,NSButton,UIButton,NSTextAttachment,WKInterfaceImage,TVMonogramViewandCPListItemto directly set an image from a URL.

Kingfisher 不仅仅给 UIImageView 添加了扩展特点 kf,它还给按钮、文本等控件添加了扩展特点。源码如下:

extension KFCrossPlatformImage: KingfisherCompatible { }
extension KFCrossPlatformImageView: KingfisherCompatible { }
extension KFCrossPlatformButton: KingfisherCompatible { }
extension NSTextAttachment: KingfisherCompatible { }

Built-in transition animation when setting images.

Kingfisher 内部供给了许多过度动画,能够在网络资源加载完的时候展现,支撑类型如下:

public enum ImageTransition {
    case none
    case fade(TimeInterval)
    case flipFromLeft(TimeInterval)
    case flipFromRight(TimeInterval)
    case flipFromTop(TimeInterval)
    case flipFromBottom(TimeInterval)
    case custom(duration: TimeInterval,
                 options: UIView.AnimationOptions,
              animations: ((UIImageView, UIImage) -> Void)?,
              completion: ((Bool) -> Void)?)
}

读源码能够看到,不仅支撑 5 中类型,还能够自定义自己想完成的类型。该功能对 UI 漂亮度要求高的 APP 开发者还是很有友好的。

动画的详细完成看源码能够知道,本质上是对 UIView.AnimationOptions 的一层封装:

var animationOptions: UIView.AnimationOptions {
    switch self {
    case .none:                         return []
    case .fade:                         return .transitionCrossDissolve
    case .flipFromLeft:                 return .transitionFlipFromLeft
    case .flipFromRight:                return .transitionFlipFromRight
    case .flipFromTop:                  return .transitionFlipFromTop
    case .flipFromBottom:               return .transitionFlipFromBottom
    case .custom(_, let options, _, _): return options
    }
}

每个动画详细的效果图,大家能够运行一下官方的 Demo 看一下。详细的逻辑在这个控制器:TransitionViewController

Customizable placeholder and indicator while loading images.

支撑自定义占位图和指示器。

public enum IndicatorType {
    case none
    case activity
    case image(imageData: Data)
    case custom(indicator: Indicator)
}

Extensible image processing and image format easily.

支撑多种图片格式,比方:PNG、JPEG、GIF等。概况可参考 官方的 Demo。

Low Data Mode support.

支撑在 Low Data Mode 的情况下,加载低分辨率的图片或许加载本地图片。

SwiftUI support.

Kingfisher 也适配了 SwiftUI,在你的 SwiftUI 项目中也能够运用它了。 示例代码如下 – KFImage

var body: some View {
    HStack(alignment: .center) {
        Spacer()
        KFImage.url(url)
            .resizable()
        Spacer()
    }.padding(.vertical, 12)
}

到这里。Kingfisher 的源码阅览就全部完成了,如果本系列文章有哪里写的不对的当地,还请读者指正。