【问题标题】:Large image URL response not cached by URLSession: Why?URLSession 未缓存大图像 URL 响应:为什么?
【发布时间】:2018-08-05 23:18:43
【问题描述】:

我使用URLSession 数据任务从后端下载多个 JPG 图像。由于图像的大小相当大(~500 KB),我想缓存相应的响应,直到它们过期(即它们已经超过了它们的 max-age)。

这是我用来下载图片的代码:

let request = URLRequest(url: url, 
                          cachePolicy: .useProtocolCachePolicy, 
                          timeoutInterval: 10.0)

let task = URLSession.shared.dataTask(with: request) { (data, _, error) in

    // Error:
    guard let imageData = data, error == nil, let image = UIImage(data: imageData) else {
        DispatchQueue.main.async {
            completion(nil)
        }
        return
    }

    // Success:
    DispatchQueue.main.async {
        completion(image)
    }
}

task.resume()

奇怪的是,这非常适用于缓存除一张之外的所有图像。出于某种原因,此特定图像总是会再次下载 - 其响应未缓存

我可以发现的响应之间的唯一区别是未缓存相应响应的图像具有最大的文件大小。虽然所有其他图像均小于 500 kB,但此特定图像略大于 500 kB。

我已经尝试过共享缓存大小并将其设置为一个高得离谱的值,但没有任何效果:

URLCache.shared = URLCache(memoryCapacity: 1000 * 1024 * 1024, 
                           diskCapacity:   1000 * 1024 * 1024, 
                           diskPath:       nil)

我检查了响应中的 Cache-Control 标头字段是否正确设置:

Cache-Control: public, max-age=86400

并且Age头域总是在max-age下面,例如:

Age: 3526

单个响应没有被缓存的原因是什么?

我该如何解决这个问题?

【问题讨论】:

  • 手动实现developer.apple.com/documentation/foundation/… 看看是否有任何变化可能是个好主意。
  • 关于大小,请注意备注:...仅当满足以下所有条件时才缓存响应:...不大于磁盘缓存大小的约 5%。我>
  • 这也是我的想法,但是我不能使用共享的 URLSession 对象(必须在实例化时分配委托),创建自定义 URLSession 也可能会改变行为。跨度>
  • 我也阅读过文档中关于大小的说明,但我认为可以肯定地说,大小约为 500 KB 的图像不到 1000 MB 磁盘缓存的 5% ...
  • 我认为如果你传入一个 nil 路径,你就不会期望得到一个磁盘缓存。你可能应该解决这个问题。但这仍然不能解释为什么它没有将其缓存在 RAM 中。

标签: ios caching nsurlsession nsurlrequest nsurlcache


【解决方案1】:

这不是问题的答案为什么共享的 URLSession 不缓存图像,我仍然感谢任何提示或回答该问题

但是,在对我的代码进行了一段时间的试验后,我发现(无论出于何种原因)当我使用具有默认配置而不是默认共享的自定义 URL 会话时,响应总是被缓存网址会话:

let urlSession = URLSession(configuration: .default)

所以如果我使用:

let task = urlSession.dataTask(with: request) { ... }

而不是

let task = URLSession.shared.dataTask(with: request) { ... }

缓存按预期工作——不管是什么黑魔法造成的。 ?


我在docs for URLSession.shared 中发现了一点提示:

在使用共享会话时,您通常应该避免 自定义缓存,...

换句话说,如果您使用缓存、cookies、 身份验证或自定义网络协议,您可能应该是 使用默认会话而不是共享会话。

【讨论】:

  • NSURLSession 缓存是每个会话的,AFAIK,唯一使用共享缓存的会话是共享会话。因此,通过这些更改,除非您还传入提供不同缓存的自定义会话配置对象,否则代码甚至不会尝试使用您创建的缓存,而只会使用具有一些合理默认值的自动创建的缓存(除非您明确地将其取消)。但不要引用我的话。
  • 您从哪里获取这些信息?据我所知,每个应用程序都有一个缓存,您可以通过URLCache.shared 访问它,所有URLSessions 都可以使用它。它使用默认缓存自动设置,但您可以通过创建自定义 URLCache 对象并将其分配给此属性来配置它。这似乎与我目前阅读的所有文档一致。
  • 我也遇到了类似的情况,我想清除 requestCachePolicy 中的缓存内容,但它似乎有效。这个答案帮助我理解了一些逻辑,但不是全部。 stackoverflow.com/a/45042040/2570153
  • 通常,在新会话上覆盖缓存的方法是在创建会话之前将新的缓存对象分配给 sessionConfiguration.URLcache。我不确定其他会话是否使用共享缓存;我认为他们实际上最终得到了一个私有缓存实例,该实例恰好指向相同的磁盘数据,但我可能记错了。无论哪种方式,使用配置中指定的不同缓存创建一个新会话肯定是有效的,并且将消除关于该会话是否实际使用您的缓存的任何疑问。 :-)
猜你喜欢
  • 2011-11-25
  • 1970-01-01
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-27
相关资源
最近更新 更多