Deep dive into Apple’s URLRequest Cache Policies

Hands-On analysis of Apple’s Cache Policies working together with a Node.js Express Server to increase API efficiency and performance

Borama Apps
Aug 23, 2020 · 5 min read
Image for post
Image for post
Photo by Cleyder Duque from Pexels

There are only two hard things in Computer Science: cache invalidation and naming things.

— Phil Karlton

Fortunately for us, Apple helps us by providing robust and powerful cache policies. Policies we should use instead of building a custom (NSCache) solution!

In this post, we’ll explore different URLRequest cache policies and the consequences of using them. Those policies apply to both iOS and macOS. We’ll use a hands-on approach looking both on server and front-end sides.

To make things easy, the Node.js Express Server (the Backend) will return strings, and we’ll log the responses in the console. (Check out the source code for both Server and App at the bottom).

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

When looking at the responses, we are looking for both Cache-Control and the HTTP Etag. There are a couple of scenarios we will look at:

  1. Cache-Control is not set, and Etag is disabled:
Image for post
Image for post

The app did connect to the server, but URLSession ignored the updated response. It might not be what we expect as 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, andEtag is changed every 2 seconds:

Image for post
Image for post

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

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

Image for post
Image for post

After receiving the first response with the max-age header set to 4 seconds, the app was hitting the server every 3 seconds. Still, the server returned the URLSession response every second with the status code 200. Secondly, the asset was updated when fetched from the server.

4. Cache-Control is set to 0 seconds, andEtagis not set.

Image for post
Image for post

We hit the server on every call, but URLSession returns the same asset each time.

5. Cache-Controlis set to 0 seconds (or not set at all), and Etag changes on each incoming request

Image for post
Image for post

We hit the server on every call, and URLSession gives us the most recent asset version. This is the same behavior we would get from using the CachePolicy reloadIgnoringLocalCacheData , always returning the latest asset version.

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

Image for post
Image for post
Image for post
Image for post

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

URLCache.shared.removeAllCachedResponses()

It seems like URLRequest.CachePolicy.returnCacheDataElseLoad is quite a dangerous policy!

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

Image for post
Image for post
Image for post
Image for post

No matter how we set Cache-Policy header or Etag, the server will be hit every second, and the latest asset will be returned. This policy should be handled with care to avoid overloading the server!

Apple describes the cache policy as: “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.”

Image for post
Image for post

And indeed, the results seen above are very similar to an offline mode. As you can see, our Express server was not hit by a request once!

Each policy needs to be directed to a unique endpoint. If the endpoints are the same, the cache will be overwritten every time we run a request with the policy URLRequest.CachePolicy.reloadIgnoringLocalCacheData !

Image for post
Image for post

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

Image for post
Image for post

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

In my opinion, we should use Apple’s caching capabilities, but some of the behaviors we analyzed above might not be so obvious after reading the documentation.

Below is the Swift code (OSX Command Line App):

And here’s our Nodejs server code:

Image for post

We are always looking for talented and passionate Swift developers! Feel free to check out our writer's section and find out how you can share your knowledge with the Next Level Swift Community!

Next Level Swift

Helping you bring your iOS applications to the next level

Borama Apps

Written by

ios, android, web apps. https://borama.co, http://twitter.com/boramaapps

Next Level Swift

Next Level Swift aims at sharing knowledge and insights into better programming for iOS and is dedicated to help developers bring their apps to the next level!

Borama Apps

Written by

ios, android, web apps. https://borama.co, http://twitter.com/boramaapps

Next Level Swift

Next Level Swift aims at sharing knowledge and insights into better programming for iOS and is dedicated to help developers bring their apps to the next level!

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store