简单图片提供器

这是一个可以方便地将图片显示到UI上的图片缓存库。

项目 内容
支持的 iOS 版本 iOS 15.0 及以上
支持的 Swift 版本 5.9 及以上
使用的技术 Swift, Swift Concurrency

正在使用 SimpeImageProvider 库的服务

项目 链接
케어밋 (Care Meet - assume this is the intended translation) App Store
soma코인뷰어 (Soma Coin Viewer - assuming this is the intended translation) GitHub

如何使用

通过访问 SimpleImageProvider.shared 单例对象,您可以使用该库的功能。

建议您在启动应用程序之前设置内存缓存大小、磁盘缓存大小以及溢出策略。

如果在其他运行时空间中执行此代码,可能会发生意外的并发问题。

class AppDelegate: NSObject, UIApplicationDelegate {
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

        SimpleImageProvider.shared.requestConfigureState(
            maxCacheImageCount: 50,
            maxDiskImageCount: 100,
            percentToDeleteWhenDiskOverflow: 20.0
        )
        
        return true
    }
}

SwiftUI 代码

实现了可以在 SwiftUI 中使用的 SimpleImage View

LazyVGrid(columns: columns) {
    
    ForEach(items, id: \.self) { item in
        
        SimpleImage(
            url:"your image url",
            size: .init(width: 100, height: 100),
            fadeOutduration: 0
        )
            .frame(width: 100, height: 100)
            .background(Color.gray.opacity(0.5))
            .cornerRadius(5)
    }
}

UIKit 代码

可以作为 UIImageView 的扩展轻松访问。

func setImage(url: String, size: CGSize) {
    
    uiImageView
        .simple
        .setImage(url: url, size: size, fadeOutDuration: 0.2)
}

代码访问

如果不是使用 UI 库而是通过代码访问,请使用单例对象。

单例对象本身已针对并发进行了优化。

await SimpleImageProvider.shared.requestImage(...)

技术特性

基于大小的图像缓存

缓存到磁盘和内存的图像都是经过降采样处理后的图像

即使是相同的图像,也会根据采样结果进行不同的缓存。

您可以在下面的缓存键值中看到包含了降采样大小。

func createKey(url: String, size: CGSize?) -> String {
    
    var keyString = url
    
    if let size {
        
        let width = size.width
        let height = size.height
        
        keyString += "\(width)x\(height)"
    }
    
    return keyString
}

降采样

图像降采样将下载的数据缓冲区更改为 CGImageSource

通过将 CGImageSource 更改为特定大小的缩略图(小于/缩减的原始图像),来执行降采样。

※ 为了直接管理图像缓存,我禁用了图像源创建和缩略图创建时的所有其他缓存选项。

func downSamplingImage(dataBuffer: Data, size: CGSize) async -> UIImage? {
    
    let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    
    guard let imageSource = CGImageSourceCreateWithData(dataBuffer as CFData,
imageSourceOptions) else {
        
        return nil
    }
    
    let biggerLength = max(size.width, size.height)
    let scale = await UIScreen.main.scale
    let maxDimensionInPixels = biggerLength * scale
    let downsampleOptions = [
        kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceShouldCacheImmediately: false,
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels
    ] as CFDictionary
    
    guard let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0,
downsampleOptions) else {
        return nil
    }
    let image = UIImage(cgImage: downsampledImage)
    
    return image
}

流程图

---
title: SimpleImageProvider flowchart
---
flowchart LR

    requestimage --> SimpleImageProvider

    SimpleImageProvider --> checkMemoryCache

    checkMemoryCache --> checkDiskCache

    checkDiskCache --> ImageDownloader

    ImageDownloader --> CacheImage
加载中

图像获取过程如下,如果图像获取失败,则跳转到下一步

  1. 图像请求
  2. 检查内存缓存
  3. 检查磁盘缓存(如果找到磁盘缓存,则立即将该图像缓存到内存中。)
  4. 图像下载
  5. 缓存下载的图像

对象映射

---
title: SimpleImageProvider class diagram
---
classDiagram
    class SimpleImageProvider {
        + requestImage(url, size) UIImage?
        + requestConfigureState(cacheSize)
    }

    class ImageModifier {
        + downSamplingImage(data, size) UIImage?
        + convertDataToUIImage(data)
    }

    class ImageDownloader {
        + requestImageData(url) Data?
    }

    class ImageCacher {

        + requestImage(url, size) UIImage?
        + cacheImage(url, size, image)
    }

    class DiskCacher
    class MemoryCacher

    ImageCacher o-- DiskCacher
    ImageCacher o-- MemoryCacher

    SimpleImageProvider --|> MemoryCacher : 1.check memeory cache
    SimpleImageProvider --|> DiskCacher : 2.check disk cache
    SimpleImageProvider --|> ImageDownloader : 3.request download & data buffer
    SimpleImageProvider --|> ImageModifier : 4.request image downsampling or convert data to image
加载中