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:

Day 11 New Project

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:

Day 11 UI

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.


Chris Risner