移动开发图像处理【免费下载链接】NukeImage loading system项目地址https://gitcode.com/gh_mirrors/nu/Nuke点击查看免费下载本文聚焦 Nuke 图片加载系统中面向开发者的缓存操作入口ImagePipeline.Cache即pipeline.cache系统讲解它如何统一封装内存缓存ImageCaching与磁盘数据缓存DataCaching涵盖读取、写入、删除、清空与缓存键管理五类 API并结合源码给出线程安全语义与请求选项的底层实现依据。读完本文你将能够在不手动拼接缓存键的前提下精准控制每一张图片在各缓存层中的存取行为例如强制刷新、仅读缓存不联网、单独操作磁盘缓存等。ImagePipeline.Cache是 Nuke 为方便开发者直接操作缓存而提供的便捷 API 集合定义于 ImagePipelineCache.swift 中。它在文档中对应的正式说明页为 ImagePipelineCache-Extension.md与 caching.md、cache-layers.md、accessing-caches.md 共同构成 Nuke 缓存体系的完整文档。一、背景三层缓存与pipeline.cache的定位Nuke 的管线ImagePipeline在加载图片时会自动查询缓存而开发者也可以通过pipeline.cache直接干预缓存内容。按照 cache-layers.md 的说明Nuke 涉及三类缓存层缓存层类型说明ImageCacheLRU 内存缓存存放已解码、可直接显示的成品图片遵循 least-recently-used 淘汰策略DataCache激进的 LRU 磁盘缓存存放原始图片数据或按DataCachePolicy决定的其它数据无视 HTTP cache-controlURLCacheHTTP 磁盘缓存属于系统 URL loading system受 HTTP 缓存头控制重要前提ImagePipeline.Cache只操作自定义缓存层ImageCaching与DataCaching不直接管理URLCache——后者由系统 URL loading system 及其 HTTP 缓存规则控制见 accessing-caches.md 的说明。默认管线使用ImageCache 增大了磁盘容量的URLCache组合而.withDataCache配置则会启用DataCache这一激进磁盘缓存。pipeline.cache是一个类型为ImagePipeline.Cache的 struct内部仅持有管线引用本质是对「缓存选择delegate 决定 缓存键生成 读写/编解码」的统一封装public struct Cache: Sendable { let pipeline: ImagePipeline private var configuration: ImagePipeline.Configuration { pipeline.configuration } }从源码结构看ImagePipelineCache.swift它不持有任何缓存对象本身而是每次操作都经由ImagePipeline.Delegate解析出当前请求应使用的缓存实例因此天然支持「不同请求命中不同缓存」的自定义场景。二、Caches选项集精确指定操作目标ImagePipeline.Cache的所有批量方法都接受一个Caches参数OptionSet用于指明本次操作覆盖哪些缓存层默认值为[.all]public struct Caches: OptionSet { /// 内存图片缓存ImageCaching public static let memory Caches(rawValue: 1 0) /// 磁盘数据缓存DataCaching public static let disk Caches(rawValue: 1 1) /// 同时覆盖内存与磁盘 public static let all: Caches [.memory, .disk] }定义见 ImagePipelineCache.swift。例如「只检查内存、不触碰磁盘」可以传入[.memory]「只读磁盘」传入[.disk]。这一设计让同一条 API 既能覆盖全层也能精确收敛到单层配合下文的方法签名即可组合出任意存取策略。三、访问已缓存的图片cachedImage 与下标语法3.1cachedImage(for:caches:)从任意缓存层取出图片返回ImageContainer?let request ImageRequest(url: url) pipeline.cache.cachedImage(for: request) // 先内存后磁盘 pipeline.cache.cachedImage(for: request, caches: [.memory]) // 仅内存 pipeline.cache.cachedImage(for: request, caches: [.disk]) // 仅磁盘会解码数据其实现顺序是若包含.memory先查内存缓存若未命中且包含.disk则从磁盘数据缓存读取原始数据并解码成图片ImagePipelineCache.swiftpublic func cachedImage(for request: ImageRequest, caches: Caches [.all]) - ImageContainer? { if caches.contains(.memory) { if let image cachedImageFromMemoryCache(for: request) { return image } } if caches.contains(.disk) { if let data cachedData(for: request), let image decodeImageData(data, for: request) { return image } } return nil }两条语义值得注意尊重请求的缓存选项若请求带有.disableMemoryCacheReads内存读取会被直接跳过见cachedImageFromMemoryCache的守卫ImagePipelineCache.swift。磁盘读取涉及解码磁盘中存的是编码后的数据读取时通过decodeImageData使用管线 delegate 选出的解码器ImageDecoderRegistry解析还原为ImageContainerImagePipelineCache.swift。因此避免在主线程调用带.disk的读取。3.2 下标语法仅内存缓存ImagePipeline.Cache同时提供两个下标直接读写内存缓存不涉及磁盘let image pipeline.cache[URL(string: https://example.com/image.jpeg)!] pipeline.cache[ImageRequest(url: url)] nil下标实现ImagePipelineCache.swift在 get 时调用cachedImageFromMemoryCacheset 时根据是否为 nil 决定写入或删除。由于它尊重请求选项下面的写法会返回nillet url URL(string: https://example.com/image.jpeg)! pipeline.cache[url] ImageContainer(image: image) // 返回 nil禁用了内存缓存读取 let request ImageRequest(url: url, options: [.disableMemoryCacheReads]) let image pipeline.cache[request]ImageContainer不仅包裹图片本身还携带元数据对动图等需要特殊渲染的图片它内部还持有data在开启isStoringPreviewsInMemoryCache时默认开启它还能用于区分渐进式解码产生的预览帧见 accessing-caches.md 的说明。四、写入、删除与检查图片store / remove / contains4.1storeCachedImage(_:for:caches:)将图片写入指定缓存层。写入内存直接存入写入磁盘则需要先编码encodeImage经由 delegate 选出的编码器见 ImagePipelineCache.swiftcache.storeCachedImage(ImageContainer(image: image), for: request)三条关键规则源码注释与实现均明确预览图永不写入磁盘缓存storeCachedImage对磁盘分支有!image.isPreview守卫ImagePipelineCache.swift。预览帧只可能进入内存且仅在isStoringPreviewsInMemoryCache开启时默认开启才会写入内存ImagePipelineCache.swift。尊重请求缓存选项内存写入受.disableMemoryCacheWrites限制磁盘写入受.disableDiskCacheWrites限制。主线程安全默认DataCache的写入是异步的先进入 staging 区域立即返回因此即使从主线程调用storeCachedImage也是安全的ImagePipelineCache.swift。4.2removeCachedImage(for:caches:)从指定缓存层移除图片。默认[.all]会同时清理内存与磁盘磁盘侧本质是移除对应数据// 先删除缓存再重新下载实现强制刷新 let request ImageRequest(url: url) pipeline.cache.removeCachedImage(for: request)实现ImagePipelineCache.swift对内存分支调用removeCachedImageFromMemoryCache对磁盘分支调用removeCachedData(for:)。4.3containsCachedImage(for:caches:)判断图片是否存在于指定缓存层返回Boollet isCached pipeline.cache.containsCachedImage(for: request)实现上先查内存再查磁盘数据缓存dataCache.containsData(for:)。注意检查磁盘涉及磁盘 IO避免在主线程调用ImagePipelineCache.swift。五、访问已缓存的数据cachedData / storeCachedData / removeCachedData / containsData除了图片维度ImagePipeline.Cache还提供一组直接操作原始数据的 API适用于需要拿到编码后字节例如自定义上传、二次处理的场景let data cache.cachedData(for: request) // 读取原始数据 cache.storeCachedData(data, for: request) // 写入原始数据 cache.removeCachedData(for: request) // 删除数据 cache.containsData(for: request) // 是否存在更便宜语义要点均可在源码中找到对应守卫cachedData(for:)受.disableDiskCacheReads限制未命中或禁用时返回nilImagePipelineCache.swift。storeCachedData(_:for:)受.disableDiskCacheWrites限制默认DataCache异步落盘可安全地从主线程调用ImagePipelineCache.swift。containsData(for:)比cachedData(for:)便宜它只做存在性检查而不读取文件内容若条目仍在 staging 区域则瞬时返回否则同步访问磁盘ImagePipelineCache.swift。线程安全总结磁盘缓存相关的读取方法——cachedData(for:)、containsData(for:)、cachedImage(for:caches:)带.disk——都是同步磁盘 IO应避免在主线程调用写入方法则因DataCache的异步 staging 机制DataCache.swift可以放心调用。六、清空缓存removeAll(caches:)removeAll一键清空指定缓存层pipeline.cache.removeAll() // 内存 磁盘 pipeline.cache.removeAll(caches: [.memory]) // 仅内存实现直接调用配置中缓存实例的removeAll()ImagePipelineCache.swiftpublic func removeAll(caches: Caches [.all]) { if caches.contains(.memory) { configuration.imageCache?.removeAll() } if caches.contains(.disk) { configuration.dataCache?.removeAll() } }一个易踩的坑它只清空管线配置中设置的缓存。如果你实现了自定义ImagePipeline.Delegate为不同请求返回了不同缓存实例那么removeAll并不会覆盖到这些「额外」缓存需要你在 delegate 层自行处理。七、缓存键管理makeImageCacheKey 与 makeDataCacheKey日常使用pipeline.cache时无需关心缓存键但 API 也把键的生成暴露出来便于诊断、调试或直接操作底层缓存如ImageCache.shared[request]的场景let request ImageRequest(url: URL(string: https://example.com/image.jpeg)!) pipeline.cache.makeImageCacheKey(for: request) // 内存缓存键 pipeline.cache.makeDataCacheKey(for: request) // 磁盘缓存键7.1 内存缓存键makeImageCacheKey返回类型为ImageCacheKey一个可哈希的透明容器见 ImageCaching.swift。生成逻辑优先检查 delegate 的自定义键否则基于请求构造默认键ImagePipelineCache.swiftpublic func makeImageCacheKey(for request: ImageRequest) - ImageCacheKey { if let customKey pipeline.delegate.cacheKey(for: request, pipeline: pipeline) { return ImageCacheKey(key: customKey) } return ImageCacheKey(request: request) }7.2 磁盘缓存键makeDataCacheKey返回String。从源码看默认键以request.imageID为基底依次拼接缩略图标识与各处理器标识ImagePipelineCache.swiftpublic func makeDataCacheKey(for request: ImageRequest) - String { if let customKey pipeline.delegate.cacheKey(for: request, pipeline: pipeline) { return customKey } var key request.imageID ?? if let thumbnail request.thumbnail { key thumbnail.identifier } for processor in request.processors { key processor.identifier } return key }这意味着「同一张原图 不同处理器」会生成不同的磁盘缓存键从而保证处理结果互不污染。7.3 自定义缓存键Delegate 钩子两个键生成方法都优先询问ImagePipeline.Delegate.cacheKey(for:pipeline:)。该协议方法的默认实现返回nilImagePipelineDelegate.swift即使用默认键自定义实现后即可完全接管键的生成例如直接使用imageIDfunc cacheKey(for request: ImageRequest, pipeline: ImagePipeline) - String? { request.imageID }自定义键同时作用于内存键与磁盘键是跨请求共享缓存例如不同ImageRequest指向同一资源的常用手段。八、底层机制与设计依据8.1 缓存选择委托给 DelegateImagePipeline.Cache不直接访问configuration.imageCache/configuration.dataCache而是通过pipeline.delegate的imageCache(for:pipeline:)与dataCache(for:pipeline:)解析ImagePipelineCache.swift。默认 delegate 实现分别返回配置中的imageCache与dataCacheImagePipelineDelegate.swift因此默认行为就是操作管线配置的那两个缓存而重写 delegate 后可以实现按请求路由到不同缓存实例的高级玩法。8.2 读写都尊重请求选项整个ImagePipeline.Cache对请求选项ImageRequest.Options保持敏感内存读取/写入分别受.disableMemoryCacheReads/.disableMemoryCacheWrites约束磁盘读取/写入分别受.disableDiskCacheReads/.disableDiskCacheWrites约束。配合 accessing-caches.md 中介绍的高级请求选项// 只查缓存、绝不联网 let request ImageRequest(url: url, options: [.returnCacheDataDontLoad]) let response try await pipeline.imageTask(with: request).response let cacheType response.cacheType // .memory、.disk 或 nil // 保留缓存但强制重新加载 let request ImageRequest(url: url, options: [.reloadIgnoringCachedData]) let response try await pipeline.imageTask(with: request).response这两者与pipeline.cache的删除/写入 API 互为补充前者在管线自动加载路径上控制缓存行为后者则提供手工干预缓存内容的入口。8.3 磁盘读写的异步语义来自 DataCacheImagePipeline.Cache磁盘方法的线程安全承诺最终由DataCache的实现保证DataCache.swift写storeData(_:for:)将变更加入 staging 区域后立即返回由后台ioQueue批量落盘flushInterval默认 1 秒见 DataCache.swift因此主线程调用安全。读cachedData(for:)若命中 staging 区域则瞬时返回否则同步读盘DataCache.swift这就是文档反复强调「读避免主线程」的原因。淘汰DataCache定期执行 LRU sweep默认 30 分钟间隔、150 MB 上限见 DataCache.swiftisSweepEnabled false可关闭以配合 App 与 Extension 共享缓存。内存侧ImageCache则是带 cost/count 上限的 LRU 缓存ImageCache.swift默认 costLimit 约为物理内存的 15%上限 768 MB并在收到内存警告时自动清空。8.4 测试佐证仓库为缓存 API 提供了专门的契约测试例如 ImagePipelineCacheAPIContractTests.swift 与 ImagePipelineCacheTests.swift覆盖了上述 API 的存取行为与选项语义可作为深入理解与二次开发的参考。九、实践速查将本节要点汇总为可直接套用的操作模式let pipeline ImagePipeline.shared let request ImageRequest(url: url) let cache pipeline.cache // 读取内存优先磁盘兜底磁盘读取涉及 IO 与解码 let image cache.cachedImage(for: request) // 只查磁盘数据 if cache.containsData(for: request) { let data cache.cachedData(for: request) } // 写入内存 磁盘磁盘侧自动编码预览图不会落盘 cache.storeCachedImage(ImageContainer(image: image), for: request) // 强制刷新先删缓存再走管线加载 cache.removeCachedImage(for: request) let response try await pipeline.imageTask(with: request).response // 一键清空 cache.removeAll()关键提醒汇总pipeline.cache只作用于自定义缓存ImageCaching/DataCaching不管理URLCache。所有磁盘读取类方法cachedData、containsData、cachedImage的.disk分支涉及同步磁盘 IO避免在主线程调用。磁盘写入安全默认DataCache异步落盘。预览帧永不写磁盘写内存也仅在isStoringPreviewsInMemoryCache默认开时生效。所有方法尊重请求的缓存选项.disableMemoryCacheReads等行为随请求选项动态变化。removeAll只清空管线配置中的缓存自定义 delegate 引入的额外缓存需自行清理。缓存键可通过ImagePipeline.Delegate.cacheKey(for:pipeline:)全局自定义影响内存键与磁盘键。围绕ImagePipeline.Cache的完整文档脉络还包括caching.md缓存体系总览、cache-layers.md各缓存层配置、accessing-caches.md缓存访问实战配合本文即可覆盖从缓存配置到精细操作的全部能力。赞分享移动开发图像处理【免费下载链接】NukeImage loading system项目地址https://gitcode.com/gh_mirrors/nu/Nuke点击查看免费下载相关推荐Nuke缓存系统内存与磁盘缓存深度优化Nuke缓存系统内存与磁盘缓存深度优化 Nuke框架提供了高效的内存与磁盘缓存系统通过精心优化的LRU算法实现智能缓存管理。内存缓存采用双向链表和哈希表组合移动开发图像处理Nuke 缓存访问完全指南ImagePipeline.Cache 与缓存控制选项实战Nuke 缓存访问完全指南ImagePipeline.Cache 与缓存控制选项实战 本文是 Nuke 图片加载框架缓存访问专题的实战指南围绕 access移动开发图像处理notp库完全指南Node.js中实现HOTP与TOTP的终极解决方案notp库完全指南Node.js中实现HOTP与TOTP的终极解决方案 notp是一个轻量级的Node.js一次性密码OTP库全面支持HOTP基于计数应用安全上一篇Pyrefly 忽略指令控制指南深入解析 permissive-ignores 与 enabled-ignores下一篇Matterbridge安全最佳实践保护你的Matter设备与数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考