
Kingfisher 缓存序列化全解析CacheSerializer 协议、DefaultCacheSerializer 与 FormatIndicatedCacheSerializer 实战指南【免费下载链接】KingfisherA lightweight, pure-Swift library for downloading and caching images from the web.项目地址: https://gitcode.com/GitHub_Trending/ki/Kingfisher本指南以 Kingfisher 官方文档 CommonTasks_Serializer.md 为主体系统讲解磁盘缓存序列化的完整机制从CacheSerializer协议的设计意图到默认序列化器的内部实现再到强制指定图片格式、以及编写自定义序列化器接入setImage(with:)的完整流程。阅读完本文你将掌握如何控制图片落盘格式、如何在圆角裁剪等场景下正确保留透明通道、以及如何通过originalDataUsed影响缓存命中后的再处理行为。什么是 CacheSerializer磁盘缓存的双向翻译器Kingfisher 的内存缓存MemoryStorage直接持有解码后的图片对象而磁盘缓存DiskStorage只能写入Data。因此在图片 → 磁盘文件与磁盘文件 → 图片这两个方向之间需要一个负责转换的角色这就是CacheSerializer协议的职责。协议定义在 Sources/Cache/CacheSerializer.swift包含两个核心方法public protocol CacheSerializer: Sendable { /// 将图片序列化为 Data用于写入磁盘缓存 func data(with image: KFCrossPlatformImage, original: Data?) - Data? /// 将磁盘读出的 Data 反序列化为图片对象 func image(with data: Data, options: KingfisherParsedOptionsInfo) - KFCrossPlatformImage? /// 是否倾向于直接缓存原始下载数据 var originalDataUsed: Bool { get } }三个要素的语义如下data(with:original:)发生在存储阶段。image是经过处理器Processor处理后的最终图片original是网络下载得到的原始字节数据——如果图片来自缓存而非新下载则original为nil。image(with:options:)发生在磁盘读取阶段options携带imageCreatingOptions等反序列化所需配置。originalDataUsed协议扩展提供了默认值false见 CacheSerializer.swift表示磁盘上保存的是处理后的图片若返回true则优先缓存原始数据从磁盘加载后会重新应用处理器得到最终图片。使用默认序列化器什么都不用做绝大多数场景下你甚至不需要感知序列化器的存在。标准用法与显式指定等价// 什么都不传Kingfisher 自动使用默认序列化器 imageView.kf.setImage(with: url) // 与上面完全等价 imageView.kf.setImage(with: url, options: [.cacheSerializer(DefaultCacheSerializer.default)])默认值来自 KingfisherOptionsInfo.swift 中.cacheSerializer选项的注释说明If not set, theDefaultCacheSerializer.defaultwill be used.具体体现在该文件的parsedOptions默认属性public var cacheSerializer: any CacheSerializer DefaultCacheSerializer.defaultKingfisherOptionsInfo.swift。DefaultCacheSerializer原生支持 PNG、JPEG、GIF 三种格式其判定依据是original数据的文件头magic bytes实现在 Sources/Image/ImageFormat.swift通过比对前 8 个字节识别 PNG 特征头、0xFF 0xD8开头的 JPEG 以及GIF三个字母的 GIF 头。当格式无法识别.unknown时会退化为 PNG 表示pngRepresentation()。两个可调属性DefaultCacheSerializer并非铁板一块它暴露了两个可配置属性见 CacheSerializer.swiftpublic struct DefaultCacheSerializer: CacheSerializer { /// JPEG 等有损格式的压缩质量默认 1.0 public var compressionQuality: CGFloat 1.0 /// 是否优先缓存原始数据默认 false public var preferCacheOriginalData: Bool false }compressionQuality仅在编码为 JPEG 这类有损格式时生效取值0.0...1.0。preferCacheOriginalData置为true后data(with:original:)会直接返回original非 nil 时否则才回退为对图片编码。强制指定格式FormatIndicatedCacheSerializer当默认的跟随原图格式策略不满足需求时可以使用FormatIndicatedCacheSerializer它为所有受支持格式提供了现成的单例静态成员说明FormatIndicatedCacheSerializer.png强制以 PNG 格式序列化FormatIndicatedCacheSerializer.jpeg强制以 JPEG 格式序列化压缩质量固定为 1.0FormatIndicatedCacheSerializer.jpeg(compressionQuality:)以指定压缩质量序列化为 JPEGFormatIndicatedCacheSerializer.gif强制以 GIF 格式序列化其源码定义在 Sources/Cache/FormatIndicatedCacheSerializer.swift。值得注意的是它的降级策略FormatIndicatedCacheSerializer.swift首先尝试用指定格式编码若图片无法表示为该格式例如强制 GIF 但图片不支持则回退到original数据本身带有的真实格式最后才兜底为原图数据的 PNG 表示。例如某个 PNG 图片用FormatIndicatedCacheSerializer.jpeg序列化JPEG 不支持透明通道若图片含 alpha 通道无法直接转换就会回退为原 PNG 数据落盘避免信息丢失。实战场景圆角裁剪时强制使用 PNG 序列化器DefaultCacheSerializer以保留输入数据的原始格式为目标但某些场景下忠实还原反而有害。最典型的例子是配合RoundCornerImageProcessor做圆角裁剪圆角处理通常需要 alpha 通道来表现四周的透明过渡JPEG 本身不支持 alpha 通道若圆角图片被存成 JPEG再次加载时角落区域会被填充为白色因此应显式指定 PNG 序列化器保证透明通道在磁盘缓存中得以保留。let roundCorner RoundCornerImageProcessor(cornerRadius: 20) imageView.kf.setImage(with: url, options: [.processor(roundCorner), .cacheSerializer(FormatIndicatedCacheSerializer.png)] )在 FormatIndicatedCacheSerializer.swift 的文档示例中官方给出了更完整的头像场景对 44×44 的图片做全圆角处理后使用 PNG 序列化器The image will always be cached as PNG format to preserve the alpha channel for the round rectangle并从缓存加载后依然是圆角效果。这一行为也体现在 Kingfisher 官方 Demo 的实践里——Demo 项目中RoundCornerImageProcessor与序列化器组合的使用可参见 Demo/Demo/Kingfisher-Demo/ViewControllers/ProcessorCollectionViewController.swift。编写自定义序列化器当默认实现与格式指示实现都无法满足需求例如接入私有加密格式、WebP 扩展、服务端定制的位图协议时可以让自定义类型遵循CacheSerializer实现data(with:original:)与image(with:options:)两个方法即可struct MyCacheSerializer: CacheSerializer { func data(with image: Image, original: Data?) - Data? { return MyFramework.data(of: image) } func image(with data: Data, options: KingfisherParsedOptionsInfo?) - Image? { return MyFramework.createImage(from: data) } }随后通过.cacheSerializer(_:)选项传入setImage(with:)let serializer MyCacheSerializer() let url URL(string: https://yourdomain.com/example.png) imageView.kf.setImage(with: url, options: [.cacheSerializer(serializer)])需要留意两点实现细节自定义序列化器同样接收original参数可据此判断数据来源下载 vs 缓存并决定是否复用原始数据。若实现originalDataUsed返回true请确保在image(with:options:)返回的是未处理的图片由 Kingfisher 在读取后自动套用处理器。序列化器在缓存管线中的调用位置从源码可以确认序列化器在两条路径中的确切位置写入磁盘ImageCache.swift 中存储图片到磁盘前调用serializer.data(with: image, original: original)若返回nil则触发KingfisherError.cacheError(reason: .cannotSerializeImage(...))错误。读取磁盘ImageCache.swift 中从diskStorage读出Data后调用options.cacheSerializer.image(with: data, options: options)重建图片随后视backgroundDecode选项决定是否再解码。可见序列化器直接影响磁盘缓存的存取两端是整个缓存链路中可插拔的关键扩展点。深入理解 originalDataUsed缓存命中后是否再次处理originalDataUsed直接决定了磁盘缓存的内容形态与后续行为测试用例 Tests/KingfisherTests/KingfisherManagerTests.swift 用两个对称用例验证了这一点默认行为originalDataUsed false磁盘保存的是处理器处理后的图片。第二次读取cacheType .disk时处理器不再执行因为磁盘上已是成品对应测试testCouldProcessAgainWhenSerializerCachesOriginalData的反例部分。preferCacheOriginalData true即originalDataUsed true磁盘保存原始下载数据第二次从磁盘加载后会重新应用处理器测试断言XCTAssertTrue(p2.processed)。var s DefaultCacheSerializer() s.preferCacheOriginalData true let options: KingfisherOptionsInfo [.processor(p), .cacheSerializer(s), .waitForCache]这一开关的取舍取决于业务希望缓存即最终形态、读取零开销保持默认希望同一份原始数据可被不同处理器复用则开启原始数据缓存。小结CacheSerializer协议是磁盘缓存的数据翻译层Kingfisher 官方文档 CommonTasks_Serializer.md 提供了从默认到自定义的完整接入路径。默认情况下使用DefaultCacheSerializer.default自动识别 PNG/JPEG/GIF无需任何配置。涉及透明通道圆角、蒙版、贴纸时务必使用FormatIndicatedCacheSerializer.png防止 alpha 信息在 JPEG 落盘时丢失。自定义序列化器只需实现两个方法即可接入私有格式或第三方编解码框架善用originalDataUsed可以精确控制缓存原始数据 读取时再处理的缓存策略。【免费下载链接】KingfisherA lightweight, pure-Swift library for downloading and caching images from the web.项目地址: https://gitcode.com/GitHub_Trending/ki/Kingfisher创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考