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 Comments

  1. I am trying to upload a React Native mobile app with Rails backend to an iOS emulator and have been seeing an error message that no bundler URL is present. Several posts on SO pointed to the appDelegate.m file as being related. I changed the jsCodelocation but had no change. Is the appDelegate.m like the entry file? It kinda looks like a bundle type file.

  2. hi.
    it shows ” ARC Semantic issue” at this part ” [self.firstDiceView showDice:roll];
    [self.secondDiceView showDice:roll2];

    ” and i couldnt sove whats wrong in this code. ive checked all the spelling tho

  3. Great tutorial! I’ve got to the point where I should be seeing the basic table presented at the end of 4.4, updating for swift 3 as I go, but can’t seem to get things just right. Wondering if there is any update here or whether I can post my codefor support? (specifically HomeModel.swift)

    On a completely separate note, does anyone know whether the intermediate course deals with more in depth tutorials surrounding databases?

    Thanks in advance kind strangers!

  4. I have made a project with Objective C, but it is not running on different mac os,what is the problem ,pls help me asap

        • Chris, has this tutorial been updated to include Swift 3 and WKWebView? I’m specifically interested in building a webview app for my word press website so this would be the determining factor on whether or not I’d want to buy in.

  5. Hey Chris, thanks a ton, one of the best and simple tutorials. I just have a question, if I have two tables: categories, and quotes. I retrieve the categories like locations in your tutorial, but depending on the category the user chooses, I want to retrieve the quotes, my SQL statement would be “SELECT * FROM quotes WHERE category=’categoryExample'”. Now, how would I change the php and let the server know what I am requesting dynamically? Thanks in advance

  6. I have a question: I started my first cxode project, for which I used youre tutorial for soundboard app but when I run it in the iphone on my mac (the standard command run) it shows the app but it isn’t scaled good! how can I fix this?

  7. I just want it to play sound, not open an app. what is the code to do this? i just want to play an mp3 file using the main.cpp file. is there no 1 line code to do this simple task??

  8. I am having running into several errors regarding my HomeModel.swift file and my viewcontroller. Is there any updated version of HomeModel for swift 3 and Xcode 8.2.1? This would be incredibly helpful!

  9. Excellent tutorial, thank you Chris.
    However when I create the solution I do not see the header file .h or .m anywhere. I have Xcode 8.2.1

  10. The code is working well for me in swift 3, but i have the problem that it keeps old data in the cache (it shows data even if i don’t have internet connection). I know you have talked about it, but i don’t know where to change the caching policy of the URLRequest instance

  11. My main concern is do these app builders display the wordpress plugins? Specifically Visual Composer or other layout plugins that house content areas?

  12. Are there newer instructions for this. Do you need a paid developer account and what about the newest xcode version. What is different?

  13. Hey Chris I keep getting a “thread 1: breakpoint 1.1” message in a green highlighted line of code in this function:

    func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return pickerData[row]
    }

    With Swift 3 on Xcode 8.2.1 it required me to alter the code to:

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return pickerData[row]
    }

    I can’t seem to find the error nor the sollution to this problem.

  14. Hey Chris. So, when using this method to create apps, are you basically having to create these intermediate PHP pages for everything you want your app to do? i.e. if, on my website, I have a profile page, to display the profile page in my app, I also have to create an intermediary (service) PHP page for the app to interact with just for that profile page and if I want the user to login, I need a login/auth service page for each “page” within the app? Thanks for your help!

    • Exactly that’s what i have been trying to do and works fine since you’re trying to pull different information for different view controller. Hope there’s no other option i have seen so far rather than specifying different end points. @CraigLil:disqus

        • Yap, same way sir but ensure you protect your moving data with https and other security methods to prevent theft in API keys and all sensitve data

  15. hello Chris
    I am getting this response in console but i want to get status value and use it to check with url and then navigate to next view controller..Thanks for help .

    {“status”:”success”,”user_id”:”58″,”user_name”:”Kundan”,”result”:”You have been logged in successfully”}

    • i have checked with url and now it is working but when i entering username or password in textfield and after that if their is space the app crashes. How can i fix this problem. Plz Chris reply it’s urgent ?

  16. Nice article! However I’m struggling with the HomeModel. I’ve followed all the Swift3 suggestions, but still get 2 errors I can’t figger out. I added a screenshot as reference.
    Error 1: ‘URLSession’ produces'()’, not th expected contextual result type ‘URLSession!’
    Error 2: Value of type ‘HomeModel’ has no member ‘parseJSON’

    Anyone knows how to solve this?

    https://uploads.disquscdn.com/images/67a46fd59b9029706c488e7c36d3a6f08f12caff34a12a4be0709a42039c6244.png

  17. 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!!

  18. 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?

  19. 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!

  20. 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

  21. 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

  22. 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?

  23. 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)”

  24. Hi

    Thanks for it.

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

    Regards,
    Hemalatha.Marikumar

  25. 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!

  26. 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!

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

  28. 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??

  29. 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?

  30. 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?

  31. 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?.

  32. 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 🙂

  33. 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()

  34. 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!

  35. 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

  36. 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).

  37. 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…

  38. 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
Share
Buffer