Large image URL response not cached by URLSession: Why?

2k Views Asked by At

I use a URLSession data task to download several JPG images from a backend. As the images are rather large in size (~500 KB) I want to cache the respective responses until they have expired (i.e. they have exceeded their max-age).

This is the code I use for downloading the images:

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()

Curiously, this works great with caching for all images except for one. For some reason, this particular image is always downloaded again – its response is not cached.

The only difference between the responses that I can spot is that the image whose corresponding response is not cached has the biggest file size. While all other images are < 500 kB, this particular image is slightly > 500 kB.

I've played around with the shared cache size and set it to a ridiculously high value, with no effect:

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

I've checked that the Cache-Control header field is correctly set in the response:

Cache-Control: public, max-age=86400

and the Age header field is always below max-age, for example:

Age: 3526

What could be the reason for a single response not to be cached?

How can I fix this?

1

There are 1 best solutions below

4
Mischa On

This is not an answer to the question why the shared URLSession does not cache the image and I'm still grateful for any hints or answers to that question.

However, after experimenting some time with my code I figured out that (for whatever reason) the response is always being cached when I use a custom URL session with a default configuration rather than the default shared URL session:

let urlSession = URLSession(configuration: .default)

So if I use:

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

instead of

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

the caching works as expected – whatever black magic is responsible for that.


I found a little hint in the docs for URLSession.shared though:

When working with a shared session, you should generally avoid customizing the cache, ...

In other words, if you’re doing anything with caches, cookies, authentication, or custom networking protocols, you should probably be using a default session instead of the shared session.