Welcome to Day 11 in the 31 Days of iOS. Today we’re continuing a subset of articles that deal with data storage. The last article focused on using the AppDelegate or a singleton to make data and functionality accessible between different view controllers. Today we’ll start looking at how to persist data between runs of your application. This will allow you to save and restore data even if your application stops running or the user restarts their device. The technique we’ll look at today is using NSUserDefaults. We’ll be starting with a brand new project, but if you’d like to follow along with the completed code, you can access it here.
Creating our project and handling the UI
Open up Xcode and choose File, New, Project. We’ll use a Single View Application and name it DayEleven:
Let’s start by putting some simple controls on our UI for testing. Open MainStoryboard.storyboard and drop two Round Rect Buttons and a Label on the view. When you’re done, your app will look like this:
Once that is done, open the Assistant Edtior in the Utilities panel on the right side of Xcode. Control + Click and drag from the buttons to your View Controller and create actions for them. Do the same for the label and create an outlet. When you’re done, your code will look like this:
Now that our UI is done, let’s look at how to use NSUserDefaults.
Writing to and reading form NSUserDefaults
NSUserDefaults gives you a way to save key value pairs in a way that will persist even when your application closes. You can think of NSUserDefaults as being very similar to a NSDictionary but one that has plumbing in place to write and read to storage. The easiest way to use NSUserDefaults is to call the class method standardUserDefaults like this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
If you read the last article, this should look familiar. The call to standardUserDefaults is essentially returning a singleton instance of NSUserDefaults. Any future calls to standardUserDefaults will return the same thing. Note that you don’t have to use the standard and you can create custom instances using initWIthUser or init, however, unless you have a specific reason not to, I’d recommend sticking with the default. Once you have an instance of NSUserDefaults you can set and read values just like when using an NSDictionary. So here, we’re saving an NSString:
When it comes to loading the data, we again get a reference using standardUserDefaults and then use objectForKey to pull our data back out:
If you run your app now and tap the Save and then Load buttons, you’ll see the My saved data string is loaded back into the UI. However, if you kill the app, or the simulator, immediately after saving the data and then rerun your app and tap the Load Data button, nothing will show up. Let’s look at why.
Staying in Sync
When you save and load data using NSUserDefaults, it doesn’t write it directly to file storage to prevent having to do file IO each time you access the defaults. This is fine when loading data, but when you save data, you may want to ensure it’s written to the file system right away. Doing so will ensure that if your app crashes or the phone turns off, or the user leaves your app, the defaults are saved right away. This is easy to accomplish by calling the synchronize method on the defaults:
Now if you kill the app immediately after tapping the Save Data button, you’ll be able to tap Load Data and see My saved data show up in the UI. You don’t have to call synchronize yourself. NSUserDefaults will periodically synch itself if you don’t need to guarantee that the data has been written to storage.
What can you save?
Today we've just seen a simple example of saving a NSString. As you might imagine, you can save many other data types. In fact, the majority of simple data types can be written to defaults including:
- NSString
- NSNumber
- NSDate
- NSArray
- NSDictionary
- NSData
What’s really great are the last three items listed. If you’re already keeping data in a NSArray or a NSDictionary you can put them into defaults without changing anything. The nice thing about being able to store NSData is that you can encode any custom object types you’ve created into NSData and then store that into defaults.
When should you use NSUserDefaults
Depending on the application you are building, you can get very far with NSUserDefaults. In fact, it can be used to save quite a bit of data for a single application. There are other options such as saving plist files and core data which you can look at if you need to have data in a format you can query or want it to be relational. We’ll look at some of these methods but if your data is in types easily put into defaults and you don’t need a more relational database approach, NSUserDefaults should work for you.
Conclusion
Today we took our first look at how to persist data between runs of your application. NSUserDefaults allows you to save data very easily and in several different formats. You can look at the finished source code here.
16 Comments
Craig Hewitt
super helpful! thanks for posting. what are the suggestions on when to use NSUserDefaults and when to use NSDictionary?
Chris
NSDictionary is a data structure you can use in Objective-C to hold name-value pairs in memory. NSUserDefaults is a technique for storing data in the device's file system so it will be available the next time the app runs (as well as to different areas of your application). It's possible to store a NSDictionary in NSUserDefaults if you want to.
Thomas Ross Camelo
when I do this in xcode 5 I get the following problem:
{
[super viewWillAppear:animated];
self.dataLabel.text = [self.dataObject description];
}
- It says property 'dataLabel' not found on object of type 'DataViewController *'
Could you tell me how to fix this urgently as this is due tomorrow?
Chris
Sorry this is so late. It sounds like you never connected your label as an outlet on your DataView Controller. To do this, go to your storyboard, select the view controller, then go to assistant mode (the tux symbol) and control drag from your label to the interface area of your controller's code to create a new outlet.
Saskia Beeldman
Great article, could you tell me what happens if there is an update of my app, will it overwrite the NSUserDefaults or is this stored separate on the device and not affected by updating an app???
Chris
NSUserDefaults will be persisted through app updates. If the user deletes and reinstalls your app though, they're gone!
Anam Mana
hello Chris, good this info, can we see an example of how to save/load an image loaded from code using NSData?
Chris
Hello Anam, check out this answer on Stack Overflow: http://stackoverflow.com/qu.... You can also take a look at the source code for the LensRocket app I made which pulls down images from the web and loads them with NSData: http://chrisrisner.com/Lens...
ihsan
hello Chris..
I'm new on iOS, if I create NSUserDefault in A view controller like this NSUserDefaults *myData = [NSUserDefaults standardUserDefaults];. How can I get myData in other controller?
Chris
Same exact code. The NSUserDefaults standardUserDefaults is accessible from anywhere within your ap.
prathima
thanks itz helpful :)
Chris
Happy to hear it.
i am noob
where you get the saving data.m?
Chris
Can you give more detail on what you're asking?
Noobie
How do i go about doing this in swift?
Narasimha Nallamsetty
this is simple and very nice..thank you