【问题标题】:URLSession cache only仅 URLSession 缓存
【发布时间】:2024-01-15 04:29:01
【问题描述】:

有时我只想在使用 URLSession 时从缓存中获取数据。例如,当在 UITableView 中快速滚动时,我想显示已经在缓存中的图像,但不触发任何 HTTP 请求。图片只是一个例子,可以是任何东西。

所以我目前正在研究 URLSession 的 CachePolicy,但它不支持仅从缓存中获取有效(未过期等)数据的选项。

我可以自己查看 URLCache,但这当然也会返回可能过期的数据。是否有一些 API 可以验证 CachedURLResponse?因为那时我可以自己做。还是我必须自己实施验证。

【问题讨论】:

  • 对于图像缓存使用 SDWemImage 库
  • @ManishMahajan 图片是一个例子,可以是任何东西。
  • @inokey 我认为这与您提供的链接不重复。我添加了图像作为 HTTP 请求的示例。真的可以是任何东西。同样在链接中,他使用额外的字典将它们保存在内存中。我想避免这种情况,因为 URLSession 已经在 URLCache 中这样做了。
  • @Haagenti 尝试查看 304 http 状态码。我记得我用它来确定是否应该从缓存中获取内容。不幸的是,我记不起更具体的了。
  • @inokey Mmm 不确定 304 状态代码是否可以解决问题,因为缓存中只包含原始响应,很可能是 200 响应。

标签: swift nsurlsession foundation


【解决方案1】:

这是一个相当不寻常的要求。通常,您要么编写代码以在离线模式下运行(在这种情况下,无论缓存的结果是否仍然有效,您都想从缓存中提取)或者您在线(在这种情况下,您想获取新数据,如果无效)。

我会鼓励您认真考虑是否真的要在不触发网络请求的情况下强制缓存验证。

也就是说,如果你真的想要这种行为,有两种方法可以做到:

  • 使用NSURLRequestReturnCacheDataDontLoad 并自己验证缓存响应的年龄。
  • 在自定义会话中执行请求,使用NSURLRequestUseProtocolCachePolicy,并在该会话中安装自定义NSURLProtocol 子类,覆盖initWithTask:cachedResponse:client:startLoading,并在顶部提供的客户端上调用URLProtocol:didFailWithError:startLoading 方法。

第二种方法可能是最好的选择,因为您不必担心了解缓存验证的所有深奥规则。通过使实际加载失败,缓存将正常工作,但一旦它实际开始发出网络请求,您的自定义协议就会阻止这种情况发生。而且因为您将仅在该特定会话中注册协议(通过会话配置中的 protocolClasses 数组),它不会破坏其他会话中的网络。

【讨论】:

  • NSURLRequestReturnCacheDataDontLoad :“使用现有的缓存数据,无论年龄或到期日期,如果没有可用的缓存数据则失败”。我只想要有效的数据。
  • 已更新。自定义协议方法稍微复杂一些,但仍然比缓存验证简单得多。 :-)
  • 我将实施您的第二种方法,这在我看来也是最佳选择。谢谢。
  • 您可能会发现这最终的工作方式与从缓存中提取所有内容相同。如果是这样,那么唯一的选择是#1。