Preventing NSURLConnection Cache Issues

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!

129 thoughts on “Preventing NSURLConnection Cache Issues”

  1. Awesome article Chris! Thank you. I’ve modified my code so when the user makes a selection from the picker, the pickerData is sent to a textField (I might change that to a label instead). My question is, how do I allow the user to input their own data from a textField into the pickerView? Everything I’ve searched for gives me the exact opposite, unless I’m wording my google search wrong. Thanks again for the great tutorials!!

  2. Chris, this article is great ! Exactly what I was looking for. I’ll for sure check out your other posts.
    I’m close to have it working but I keep on hitting the error:
    Could not cast value of type ‘__NSArrayI’ (0x108b81c08) to ‘NSMutableArray’ when it tries to parse the JSON stream. Any idea?

    Also the JSON stream viewed through the browser does not look exactly the same. I get something like:
    [{“ID”:”test”,”Nom”:”test”,”Date”:”test”,”MJ”:”test”},{“ID”:”test2″,”Nom”:”test2″,”Date”:”test2″,”MJ”:”test2″}]

    Can it be the problem?

  3. Chris. This is greatness. You are killing it in the SERPS as well. Good for you.

    Wondering can you have an app that is basically a hybrid of the two? i.e. I want to have a QR Reader in my app, but that isn’t really something that is native to PHP. So, could the bulk of my app be a web based app, but then at the bottom I have a QR link and when they click it, it goes into native iOS functionality?

    Thanks much!

  4. Hi Chris, Thank you for posting this,

    I am facing an error in my ViewController.m on line 24 self.webView loadRequest: requestWithURL: url]]; it says property webView not found on object of type ViewController

  5. Hey I’ve got a problem, we have an app made with unity and we have some PHP files that connect with a MySQL database to make a Register and Login, I’m usig Post methods to insert the data into the database, and It works on android, but I can’t make the connection with iOS because the iOS device don’t register the data into the database 🙁 i need help

  6. I just started using Xcode (8.0). I created a test file with Swift and as iPhone7+, dropped a button on the storyboard, changed the title of the button. Ran it with a Successful Build but when the Simulated phone pops up the button is not displayed, why not?

  7. Excellent article. I’m using Swift 3 and Xcode 8 and don’t know how to fix some of the errors, especially this part ” session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: nil)”

  8. Hi

    Thanks for it.

    Is that having stacklayout to add one ore more elements like as in android?.

    Regards,
    Hemalatha.Marikumar

  9. Hi all,

    this line of code is generating an error for me: session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)

    the error states: ‘URLSession’ produces ‘()’, not the expected contextual result type ‘URLSession!’

    anybody know how I can work around this?

    Thanks!

    • It compiles cleanly if you use:
      session = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: nil)

      Groan!

  10. I experienced problems from the start. The instructions were not very clear and I couldn’t even make a DemoDice header file!!!
    On to the next

    Bye!!!

    • Hey! did you ever figure this out? I’m having the same issue now…can anyone help? I just get an empty table view, no run error. but I do get errors seems from trying to connect to database ; nw_host_stats_add_src recv too small, received 24, expected 28 …any help would be great guys!

  11. Hello chris, how can i use the delegate methods of the tabbarcontroller? for ex: tabBarController:shouldSelectViewController:

  12. Hi, can I create an Archive for Distribution even if I don’t connect an iOS device to my Mac? Can I use “Generic iOS Device” to create the archive??

  13. Hi I am super new to IOS development. but I have an app in mind that I want to build which will be an offline dictionary, English to Kurdish (and vise verse). so can you please guide me how to start it?

  14. In the beginning of the tutorial, you mentioned we don’thave to actually transfer our domain but rather change some configurations settings. “… you don’t actually have to transfer the domain to Bluehost. Rather, you just have to go to your registrar where you registered your existing domain name and then change some configuration settings to point to Bluehost.” How do I do this?

  15. nice tutorial,
    this tutorial wrote code to get that font.. but can I be able to design on storyboard and select that font to use it on the properties?.

  16. Easy to follow, thanks! Also, these fonts now become available from the dropdown if you’re editing labels from the storyboard UI’s as well. Very handy 🙂

  17. Thanks for this – still relevant, and the bit about font names not being what you expect still catches me out.

    Here’s the font name dump code converted to Swift 3:-

    for family: String in UIFont.familyNames
    {
    print(“(family)”)
    for names: String in UIFont.fontNames(forFamilyName: family)
    {
    print(“== (names)”)
    }
    }

    • This would great if possible. Xcode 8 with Swift 3 I get quite a few ‘corrections’. The one stumping me is in func downloadItesm()

      let configuration = URLSessionConfiguration.default

      session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)

      let task = session.dataTaskWithURL(url as URL)

      task.resume()

  18. super thanks for your article! i was struggling to get simultaneous audio playback when recording video+audio. i’ve been using AudioServicesPlaySystemSound and because of that when recording i didn’t have playback. with AVAudioPlayer it’s working fine!

  19. Hello Chris, I can run my app but there is a problem to fix such as the app doesn’t showing the map very well, or it just move to the next screen and the map doesn’t appear like a map, like a yellow screen with a plaid.

    help me to fix this, and thank you very much your tutorial is pretty good. *thumbsup

  20. I get an error when I run this. I changed the JSONSerialization from NSJSONSerialization since it’s been changed in xcode.

    jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSMutableArray

    The error is: Could not cast value of type ‘__NSSingleObjectArrayI’ (0x10e2bdbe0) to ‘NSMutableArray’ (0x10e2bdcd0).

  21. Hai Chris , I used this NSUrlConnection Example tutorial to Download a Image But I troubled now to Display the Image and by using the recieved bytes I want to calculate the progress View How could I get the Total file size that I download from the given URLRequest…

  22. Thanks so much, man! I could not figure out what was wrong with my code until I found your post. You saved my day! Many thanks and other posts are very informative as well. Looking forward to reading more great ones.

Leave a Comment

Share
Tweet
Pin