Network Caching on iOS Mobile Devices using HTTP Cache Headers

Last Updated: 07 February 2014

caching ios mobile

Table of Contents

One of the most straight-forward ways to improve user experience is to make things faster. For iOS apps that communicate with a web API one of the best ways to do this is by caching network requests. Employing effective caching strategies can make your app fast and responsive by reducing the number of requests made to the server and persisting data between launches.

Properly setting HTTP response headers in your web-API and taking advantage of iOS’s system-level network caching is a simple to implement strategy that can materially improve the performance of your mobile app.

HTTP headers

Contained within every HTTP request/response is a set of metadata transferred as HTTP headers. This metadata describes request/response mime-type, status codes and several cache directives.

Response headers

When a client makes a request to a server, the HTTP response includes a set of HTTP headers, including some which serve as directives for how that response should be cached:

  • Cache-Control - This header must be present in the response from the server to enable HTTP caching by a client. The value of this header may include information like its max-age (how long to cache a response), and whether the response may be cached with public or private access, or no-cache (not at all). See the Cache-Control section of RFC 2616 for full details.

In addition to Cache-Control, a server may send additional headers that can be used to conditionally request information as needed:

  • Last-Modified - The value of this header corresponds to the date and time when the requested resource was last changed. For example, if a client requests a timeline of recent photos, /photos/timeline, the Last-Modified value could be set to when the most recent photo was taken.
  • Etag - An abbreviation for “entity tag”, this is an identifier that represents the contents requested resource. In practice, an Etag header value could be something like the MD5 digest of the resource properties. This is particularly useful for dynamically-generated resources that may not have an obvious Last-Modified value.

Request headers

Once a client receives a response with any of these cache headers, their values can be sent on subsequent requests to conditionally ask the server for information only if the resource has changed:

  • If-Modified-Since - This request header corresponds to the Last-Modified response header. Set the value of this to the Last-Modified value received from the last request to the same endpoint. If the resource has not been updated since the last request, the server will send a 304 (not modified) status code response.
  • If-None-Match - This request header corresponds to the Etag response header. Use the Etag value received previously for the last request to that endpoint. If the value on the server is the same as requested by the client, then the resource has not been changed, and a 304 (not modified) status code will be returned.

Server-side cache headers

Web frameworks of all languages support easily declaring the Cache-Control and conditional headers. By way of example, the Sinatra framework in Ruby provides several helper methods that cleanly map to their header equivalents:

app.rb

class App < Sinatra::Base

  get '/founders' do

    # ...
    cache_control :public, :must_revalidate, :max_age => 86400
    last_modified Date.today
    etag Digest::MD5.hexdigest(@founders.to_s)
    # ...

  end
end

Sample code for this reference application is available on GitHub and can be seen running at http://floating-wind-3377.herokuapp.com/founders.

Visibility

There are a variety of browser-based tools that let you see the headers returned by your API including Firebug and Google Chrome’s built-in developer tools. Here you can see both the request and response cache-related headers when making a request to the sample application at http://floating-wind-3377.herokuapp.com/founders.

Cache headers introspection w/ Google Chrome developer tools

iOS network caching

The URL Loading System built-into Foundation classes like NSURLConnection and NSURLCache, as well as frameworks that leverage them, such as AFNetworking will correctly follow HTTP directives sent from the server.

Heroku recommends CocoaPods as the preferred way to manage Xcode project dependencies, such as AFNetworking. See the article Getting Started with iOS Mobile Development and a Sinatra API for additional information.

NSURLCache automatically manages the caching behavior of incoming and outgoing network requests that use NSURLConnection. If a cached response is available, NSURLCache will transparently return the cached response without making a network request.

With a few simple adjustments, your iOS app has taken advantage of the powerful caching infrastructure provided by Foundation classes and HTTP.

Further reading