Build a Sample iPhone App that Saves a User's Session Data with NSUserDefaults
Introduction: Create a Great User Experience
If your app requires any kind of workflow or data entry, it is best to save app state periodically upon shutdown. Otherwise, users can lose all of their work. This would not only be a loss of data but also of time.
One of your main goals is to create a great user experience. In regards to saving data and app state, NSUserDetaults
can help you accomplish this. It doesn't require too much work but the rewards to the user can be enormous.
What is NSUserDefaults
NSUserDefaults
is a singleton class that lets you save data without the user even knowing it. It provides a seamless experience for the user. You choose which data to store in NSUserDefaults
, synchronize it and that's it. Instant app state saved!
If you want to read the full Apple developer documentation, you can find it here.
The App
To demonstrate how NSUserDefaults
works, we going to build an app. We'll focus on NSUserDefaults
and not so much on building a polished off UI.
The app we'll build is a single view app with two input fields and two buttons. The user will enter their data into two fields and click a save button. Upon click of the button, we'll also save their data behind the scenes.
We'll also have a clear button to remove data from the input fields. This clear button will have a dual purpose. Once data has been cleared from the input fields, the button text will change from clear to load. Clicking the button in this state will load the data into our input fields, which was previously saved into NSUserDefaults
.
When the user reopens the app and clicks the load button, we'll grab their data from NSUserDefaults
and popular the text fields.
Below is a screenshot of the final app:
Creating The Project
To create the project, start up Xcode and select Single View Application for your project type. Once the project is open, click Main.storyboard. Click the view controller icon at the top of the scene as shown below:
We're going to resize the scene to an iPhone 6. Bring up the Attributes Inspector and in the Size drop down, select iPhone 4.7 inch.
Creating The UI
Now we can begin working on the UI. Start by adding two labels to the left side of the screen, flush against the left margins. Double click each label to start typing. Type in the following respectively:
First Name
Last Name
Now drag two text fields onto the screen just below each label. Align them to the left margin as well. Drag the width of each text field to the right margin so they stretch across the screen.
Drag a button onto the screen and below the input fields. Change the text to "Save". Drag the width to each margin so it stretches across the screen.
Click the Attributes Inspector for the button and change its background to Light Gray. Click the Size Inspector and change the height to 70.
Do the same for the Clear button.
Binding The Model To Our UI
Now we can begin binding our model (ViewController class) to the UI. This means we'll be able to capture data the user is typing into our input fields. This will be done by recognizing the user has clicked the Save button, which will also be bound to the UI.
Here are the steps to complete the binding: Click on Main.storyboard in the left pane. This opens our main and only scene.
We want to view the Assistant Editor and hide the Utilities. At the top right of Xcode, click the two interlinked circles just above the left red arrow in screenshot. This will show the Assistant Editor. We can also hide the Utilities pane to make more room. Click the icon just above the right red arrow in the screenshot to do this.
To create a UI reference to our input fields, click on the first name TextField. Click the control key and drag into the Assistant Editor, just above viewDidLoad()
. This will open a window to create an IBOutlet. Type in the name firstName.
Do the same for the last name TextField and give it the name lastName. We can also create a reference to capture the Save button click. Control drag from the Save button to the Assistant Editor, just under viewDidLoad()
this time.
You'll get the same popup window. We're going to create an Action, which is a function instead of a property. We need a function since we are capturing an event from this UI element versus just needing a reference to it (as we did with first and last name TextFields).
In the Connection dropdown, select Action. Give it the name saveButtonClick
.
Add another button and type in Clear on the button. Now add an action for the button, just as you did for the Save button, and call it clearButtonClick
. We're going to also add an IBOutlet for the Clear button. This will allow us to change the button text at runtime. Control drag from the Clear button into the view controller (just as you did for the TextFields) and create an IBOutlet named clearButton.
Your ViewController class file should now contain the following two IBOutlets and two IBActions:
@IBOutlet var firstName: UITextField!
@IBOutlet var lastName: UITextField!
@IBOutlet var clearButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
@IBAction func saveButtonClick(sender: AnyObject) {
}
@IBAction func clearButtonClick(sender: AnyObject) {
}
NSUserDefaults
Saving To We're going to now save our TextField data to NSUserDefaults
once the save button is clicked. Add the following into your saveButtonClick function:
@IBAction func saveButtonClick(sender: AnyObject) {
let defaults = `NSUserDefaults`.standardUserDefaults()
defaults.setObject(firstName.text, forKey: "firstName")
defaults.setObject(lastName.text, forKey: "lastName")
defaults.synchronize()
println("fn=\(firstName.text), ln=\(lastName.text)")
}
Here's what's happening in this code. We start by getting a reference to the default NSUserDefaults
. This is basically a singleton so no matter how many times we call this code, it will always be the same NSUserDefaults
instance.
The NSUserDefaults
instance is then assigned to a constant named defaults. It's best to use constants when possible. This ensures there aren't any unexpected changes to your reference further down the line.
Next we have two calls to setObject()
. This is where we add anything that we want saved to NSUserDefaults
. The first parameter is the object we're saving and the second is a key that is used to later retrieve this object.
Finally, we synchronize NSUserDefaults
to ensure our data is saved immediately. Be aware of where you synchronize with NSUserDefaults
as there can be a lag with large data. But for now, this won't be a problem.
The last line is to output values captured from the UI into the console. Running the program and typing in john doe then clicking the Save button produces the following console output:
NSUserDefaults
Retrieving Data From The clear button will have two behaviors. If there is data in the TextFields, it will clear out this data. If no data exist in the TextFields, it will populate the TextFields using data from NSUserDefaults
.
Create the following loadDefaults()
function just below clearButtonClick()
:
func loadDefaults() {
let defaults = `NSUserDefaults`.standardUserDefaults()
irstName.text = defaults.objectForKey("firstName") as String
lastName.text = defaults.objectForKey("lastName") as String
}
Let's talk about what's going on in the loadDefaults()
function. The first thing we do is get a reference to the NSUserDefaults
instance. Next, we call objectForKey()
and pass in the key value we used in the buttonSaveClick()
function.
The as String code is necessary here. We are assigning values to strings (i.e., firstName.text) but those values are initially objects. The string cast ensures proper assignment as a string.
We can now populate our clearButtonClick()
function. Add the following code in this function:
@IBAction func clearButtonClick(sender: AnyObject) {
if(firstName.text == ""){
loadDefaults()
clearButton.setTitle("Clear", forState: .Normal)
}
else {
firstName.text = ""
lastName.text = ""
clearButton.setTitle("Load", forState: .Normal)
}
}
Notice how we're changing the button text depending if there is any data in the firstName TextField or not. This same logic is also used to determine if we need to load data or not.
Let's Take It For A Spin
Run the program. Type something into each field and click save. Notice your console output. Your data should now be saved into NSUserDefaults
.
Click the Clear button. The Clear button text should change to Load. Now click the Load button and notice the TextFields populate from NSUserDefaults
with our previous entries.
NSUserDefaults
Note On Simulator And Because each run of the simulator from Xcode basically creates a new app, our data won't persist across multiple simulator runs. In order to test persistence, you'll need to load the app on your iPhone. To do this, just connect your iPhone to your Mac. Select your iPhone in Xcode and run the app.
Once the app loads, type in some data and click Save. Now shut down the app. To do this, double click the home button and swipe up on the app to remove it from the screen. The app is now shut down. Tap the app icon to open it. Click the Clear button. Notice your data comes back.
I hope you have enjoyed this introductory tutorial on using NSUserDefaults
. It's a simple tutorial but it lets you see how NSUserDefaults
works. There is certainly broader use of the concepts you've learned in this tutorial.
NSUserDefaults is great solution when you just want to persist data across app sessions and don't need a large data framework or relational database, such as what is offered with Core Data.
Can you update this for Swift4? having trouble on the “func loadDefaults”
all set I figured it out, What i will attempt to do is make the load button show up if the user shuts it down then opens it. It would not be very clear for a user to hit the clear button to load the data.
Great intro though it helped me a lot.