news 2026/9/13 11:42:54

Kingfisher 出现 notCurrentSourceTask 错误时图片是否已下载缓存?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kingfisher 出现 notCurrentSourceTask 错误时图片是否已下载缓存?

Kingfisher 出现 notCurrentSourceTask 错误时图片是否已下载缓存?

【免费下载链接】KingfisherA lightweight, pure-Swift library for downloading and caching images from the web.项目地址: https://gitcode.com/GitHub_Trending/ki/Kingfisher

在 Kingfisher 中,你对一个 image view 调用setImage加载url1,在它完成前又对同一个 view 设置了url2url1的 completion handler 就会收到.failure(.imageSettingError(.notCurrentSourceTask))(错误码 5002)。常见疑问是:这个错误会不会连带中断下载?答案是不会——Kingfisher 官方文档明确说明,此时url1的下载任务照常完成,下载到的图片数据会被处理并正常写入缓存;这个错误只表示结果回来时,view 已经不再等待这个资源,所以图片没有被显示出来。

下面的内容说明这个错误的产生机制、如何判断底层任务到底是成功还是失败、以及如何核实图片确实已进入缓存。

notCurrentSourceTask 是如何产生的

错误定义在 KingfisherError.swift:

  • 每次调用setImage都会签发一个新的任务标识并覆盖旧任务的标识(见 ImageView+Kingfisher.swift)。
  • 旧任务最终完成时,Kingfisher 发现当前 view 的任务标识已经不是这个任务的了,于是把结果包装成.notCurrentSourceTask报给旧任务的 completion handler,无论该任务本身是成功还是失败
  • 该错误的关联值有三个:result(底层任务成功时的RetrieveImageResult,失败时为nil)、error(底层任务失败时的错误,成功时为nil)、source(该任务原始的Source)。
  • 错误域为com.onevcat.Kingfisher.ErrornotCurrentSourceTask对应的错误码是 5002。
  • 需要判断错误类型时可以用KingfisherError.isNotCurrentTask属性(见 KingfisherError.swift),它返回true表示"新任务开始后旧任务完成,但 view 没有被更新"。

官方性能文档 Topic_PerformanceTips.md 给出的文档示例:

imageView.kf.setImage(with: url1) { result in // `result` is `.failure(.imageSettingError(.notCurrentSourceTask))` // due to another `setImage` below. // // But the download (and cache) is done normally. } // Set again immediately. imageView.kf.setImage(with: url2) { result in // `result` is `.success` }

并明确写道:

Even if the setting forurl1ends in a.failurebecause it was overridden byurl2, the download task itself completes. The downloaded image data is processed and cached accordingly.

所以收到 5002 时,要区分两种情况,依据是关联值:

关联值含义
resultnilurl1本身下载成功,图片已处理并缓存,只是没有显示到 view 上
errornilurl1底层任务确实失败了(例如网络错误),且随后被新任务覆盖

仓库测试 ImageViewExtensionTests.swift 中的testDownloadForMultipleURLs验证了第一种情况:第一个setImage的回调收到notCurrentSourceTask,但错误关联的result里带有下载到的图片;而 view 上实际显示的是第二个 URL 的图像。

如何核实图片确实已进入缓存

下载"完成"不等于你马上能用isCached检查到,因为磁盘缓存是异步写入的。按 CommonTasks_Cache.md 的说明:

  1. 确定缓存 key。默认缓存 key 是把 URL 转成字符串生成的,网络 URL 使用absoluteString(见 Resource.swift)。所以直接用url1.absoluteString作为 key 即可;如果你用ImageResource(downloadURL:cacheKey:)自定义过 key,则用那个 key。

  2. 检查缓存位置

    let cache = ImageCache.default let cached = cache.isCached(forKey: url1.absoluteString) // 想知道缓存在哪里:`.memory`、`.disk` 或 `.none` let cacheType = cache.imageCachedType(forKey: url1.absoluteString)
  3. 如果加载时用了 processor,处理后的图片是带 processor 标识缓存的,检查时必须带上:

    let processor = RoundCornerImageProcessor(cornerRadius: 20) cache.isCached(forKey: url1.absoluteString, processorIdentifier: processor.identifier)
  4. 注意磁盘缓存的异步性。文档指出:图片写入磁盘缓存是异步的,view 扩展方法的 completion handler 执行时磁盘缓存可能尚未写完——此时查磁盘缓存可能得到nil;但内存缓存操作是同步的,图片一定已经可以命中内存缓存。如果你的逻辑依赖"handler 返回时磁盘缓存必须存在",在setImage时加.waitForCache选项,Kingfisher 会等磁盘缓存操作完成后再执行 handler:

    imageView.kf.setImage(with: url1, options: [.waitForCache]) { _ in ImageCache.default.retrieveImageInDiskCache(forKey: url1.absoluteString) { result in // 此时磁盘缓存写入已完成 } }

    如果url1加载时没有.waitForCache,而在旧任务的 handler 里立刻查磁盘得到nil,这属于文档说明的异步时序,不代表下载没完成——可以稍后再查,或检查内存缓存。

如果确认这张图片不会再显示,可以取消下载

上面的行为意味着url1即使没显示也消耗了网络、CPU、内存和电量。文档建议:如果url1的图片之后还可能再次显示给用户,这些开销换来的是缓存命中,值得;如果你确定它不再需要,就在设置新图片前取消旧任务,让旧 handler 收到.failure(.requestError(.taskCancelled))而不是 5002:

imageView.kf.setImage(with: url1) { result in // `result` is `.failure(.requestError(.taskCancelled))` // Now the download task is cancelled. } imageView.kf.cancelDownloadTask() imageView.kf.setImage(with: url2) { result in // `result` is `.success` }

cancelDownloadTask()只对还在运行中的下载任务生效,已完成的下载不受影响(见 ImageView+Kingfisher.swift)。在 table view / collection view 中快速滚动时,文档给出的做法是在didEndDisplaying里取消即将消失 cell 的未完成任务:

func collectionView( _ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { // This will cancel the unfinished downloading task when the cell disappearing. cell.imageView.kf.cancelDownloadTask() }

这样处理后,被取消任务的回调会收到.requestError(.taskCancelled)(可用KingfisherError.isTaskCancelled判断),而不是notCurrentSourceTask——两种错误的区别正好可以用来确认"下载到底跑了没有"。

小结与边界

  • 收到.notCurrentSourceTask(5002)时,图片是否已下载缓存取决于关联值resultnil表示底层下载成功、数据已处理并按默认缓存策略写入内存与磁盘缓存;errornil表示底层任务本身失败。
  • 核实时用ImageCache.default.isCached(forKey:)/imageCachedType(forKey:),带上 processor identifier(如有),并记住磁盘缓存写入是异步的,必要时用.waitForCache
  • 5002 只是"设置"阶段的错误,不代表加载流程失败;live photo 场景有对应的notCurrentLivePhotoSourceTask(错误码 5005),机制相同。
  • 详细文档可参考 Topic_PerformanceTips.md 与 CommonTasks_Cache.md。

【免费下载链接】KingfisherA lightweight, pure-Swift library for downloading and caching images from the web.项目地址: https://gitcode.com/GitHub_Trending/ki/Kingfisher

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 11:42:30

消费电子ESD整改实战:三层防御体系设计与落地

1. 从“啪”一声到整机黑屏:这副耳机的ESD问题不是偶然,是设计链上的系统性失守你有没有过这样的经历——刚摘下耳机,手指碰到金属耳罩边缘,“啪”地一声脆响,手心一麻;下一秒,耳机RGB灯带突然熄…

作者头像 李华
网站建设 2026/9/13 11:40:36

Java JDK版本演进:从JDK8到JDK21的核心特性解析

1. JDK版本演进概览Java作为企业级应用开发的主流语言,其JDK版本的迭代直接影响着数百万开发者的日常工作。从2014年发布的JDK8到2023年推出的JDK21,Java语言经历了从函数式编程基础到现代并发模型的完整进化。作为长期使用Java的老兵,我完整…

作者头像 李华
网站建设 2026/9/13 11:36:16

如何为 MLflow 接入 OIDC 身份提供商实现 SSO 单点登录?

如何为 MLflow 接入 OIDC 身份提供商实现 SSO 单点登录? 【免费下载链接】mlflow The open source AI engineering platform for agents, LLMs, and ML models. MLflow enables teams of all sizes to debug, evaluate, monitor, and optimize production-quality A…

作者头像 李华
网站建设 2026/9/13 11:35:43

如何用 PandasAI v3 语义层接入 PostgreSQL 表并用自然语言查询

如何用 PandasAI v3 语义层接入 PostgreSQL 表并用自然语言查询 【免费下载链接】pandas-ai Chat with your database or your datalake (SQL, CSV, parquet). PandasAI makes data analysis conversational using LLMs and RAG. 项目地址: https://gitcode.com/GitHub_Trend…

作者头像 李华
网站建设 2026/9/13 11:34:00

ANT9921内置升压H类功放芯片原理与实战设计指南

1. 为什么ANT9921不是“又一款普通功放芯片”——从30W单声道背后的真实供电瓶颈说起 你拆过市面上那些标称“30W输出”的小体积音频板吗?我拆过不下二十块,八成以上在满功率播放时,电源端口会明显发烫,用万用表一测,V…

作者头像 李华