Preventing NSURLConnection Cache Issues
29 Dec 2012
If you have worked with the NSURLConnection class in iOS, then you may have come across this behaviour before; we were using the NSURLConnection class to download a remote XML file to check if there was an update for our app. When we changed the XML file on the remote server to indicate there was indeed an update, the iOS application still reported that there was no update.
It turns out that you can specify a caching policy for the NSURLRequest that you pass into NSURLConnection. If you don’t specify anything (as in my case) then NSURLConnection will obey the instructions in the header of the response from the server.
From the Apple Documentation, you can specify one of the following options for the NSURLRequestCachePolicy that you pass into your NSURLRequest:
NSURLRequestUseProtocolCachePolicy: This is the default value and means that depending on what the protocol dictates, the best fitting policy will be used. You can use the “Cache-Control” and “Expires” header values that the server returns to control how iOS will cache the data. For example, if you don’t want it to cache at all, you can set the “Expires” date equal to the Date header value and “Cache-Control: max-age=0”. Check the HTTP Standards for more information.
NSURLRequestReloadIgnoringCacheData: With this setting, it will ignore local cache and retrieve the data from the source again. This is what we should have specified for retrieving remote config files.
NSURLRequestReturnCacheDataElseLoad: This setting will use a local cached copy of the data if it exists; otherwise, it will load the data from the source. This would be ideal for data that doesn’t change and just needs to be retrieved once.
NSURLRequestReturnCacheDataDontLoad: This will return a local cached copy of the data if it exists. If the data doesn’t exist in local cache, then it will return nil. It won’t attempt to retrieve the data from the source. This would be ideal for an offline mode of a news app for example.
In my case, I had not specifically set a cache policy in my NSURLRequest and the server that my XML file was sitting on did not specified a “Cache-Control:max-age” value too high so when my app was checking for updates, it was getting stale data.
We considered three different options for correcting this issue:
1. Set a caching policy on your NSURLRequest instance. This is the preferred solution and this gives you control over different caching policies depending on the resource you’re fetching.
2. Set the cache-control and expires header values in the response from the server. You’d only be able to do this for if you have control of the server.
3. You can add a random query string variable to your request URL. This will be treated as a unique and new URL. Although this solution works, it’s not ideal since Apple has provided a way via option #1 to control caching.
If you forgot to specify a cache policy for your NSURLRequest instance and your iPhone or iPad application is already in production/in the App Store, then your best bet would be to update the response headers from your server. If you don’t control the server, then you’re probably in damage control mode; update your app description and tell your users that there’s a fix coming soon!