URLRequest Cache Policy.
By: Borama Apps
Tags: Caching, App Development, Swift, iOS App Development, Programming

Let’s start with default URLRequest.CachePolicy.useProtocolCachePolicy

The official Apple’s documentation shows nice decision tree: https://developer.apple.com/documentation/foundation/nsurlrequest/cachepolicy/useprotocolcachepolicy

There are a couple of scenarios depending on how the server is set:

‘Cache-Control’ is not set, ‘Etag’ is also disabled:

The app, did connect to the server but URLSession ignored the updated response. It might not be what we expect, although we can use Etag on the server to sync the app with the server after updating the assets on the server.

2. ’Cache-Control’ is not set, ‘Etag’ is changed every 2 seconds is changed.

Now every time Etag changes, the URLSession gives us updated asset.

3. ‘Cache-Control’ is set to 4 seconds, ‘Etag’ is changed every time the server asset changes.

After receiving the first response with the ‘max-age’ header set to 4 (seconds), the app was hitting the server only every 3 seconds, but the URLSession response was returned every second with the status code 200, and the asset was updated when it was fetched from the server.

4. ‘Cache-Control’ is set to 0 seconds, ‘Etag’ is not set.

We hit the server on every call, but URLSession gives us the same asset.

5. ‘Cache-Control’ is set to 0 seconds (or not set at all), and ‘Etag’ changess on each incoming request

We hit the server on every call and URLSession gives us most recent version of the asset. This is the same behaviour URLRequest.CachePolicy.reloadIgnoringLocalCacheData would give us regardless of what is set on the server.

Now let’s try URLRequest.CachePolicy.returnCacheDataElseLoad

The Apple’s documentation says: “Use existing cache data, regardless or age or expiration date, loading from originating source only if there is no cached data.”

When we use this policy, no matter how we set (or not set) ‘Etag’ and ‘Cache-Control’ on the server, we’ll get just one “snapshot” of the asset and the server will never hit again, unless we clear the local cache, ie.:

URLCache.shared.removeAllCachedResponses()

Seems like URLRequest.CachePolicy.returnCacheDataElseLoad is quite a dangerous policy:)

What about URLRequest.CachePolicy.reloadIgnoringLocalCacheData

Apple’s documentation says: “This policy specifies that no existing cache data should be used to satisfy a URL load request.”

No matter if we set ‘Cache-Policy’ header, disable ‘Etag’ or not the server will be hit every second and the latest asset will be returned.

URLRequest.CachePolicy.returnCacheDataDontLoad

It says: “If there is no existing data in the cache corresponding to a URL load request, no attempt is made to load the data from the originating source, and the load is considered to have failed. This constant specifies a behavior that is similar to an “offline” mode.”

And indeed, it is very simliar to an “offline” mode. Our poor server was never hit!

Let’s hit our server using different cache policies at once.

They need to be different endpoints, otherwise cache will be overwritten every time URLRequest with URLRequest.CachePolicy.reloadIgnoringLocalCacheData is executed!

URLRequest.CachePolicy.useProtocolCachePolicy catches up with URLRequest.CachePolicy.reloadIgnoringLocalCacheData and URLRequest.CachePolicy.returnCacheDataElseLoad hits the server only once and doesn’t return updated asset.

This is what happens if we hit the same endpoint using different caching policies:

The URLRequest response is overwritten and the server is only hit once by URLRequest.CachePolicy.returnCacheDataElseLoad and URLRequest.CachePolicy.useProtocolCachePolicy requests.