top of page

Swift: Storing Preferences in UserDefaults

Updated: Jul 21, 2020

You can find the step-by-step instructions for this blog on my devrazor YouTube channel

You can also find the complete source code on GitHub: https://github.com/devrazor-com/storing_userdefaults_sample


There are a number of things to consider when deciding where to store different types of information.

The easiest way to store information is by using the UserDefaults class. This class makes it very easy to read and write data from the Preferences file. This file is nothing more than a standard XML file. The Preference file is named com.yourcompanyname.yourapplicationname.plist


It’s important to save the application’s current state in case you have to restore it later on - and you can use UserDefaults and the Preferences .plist file to achieve this.

However, you shouldn’t use the Preferences file to store sensitive information - unless you use strong encryption. Also, you shouldn’t use the preferences file to store large amounts of data as it can slow down your application. The data that you store is both read and written at the same time although UserDefaults caches the information to avoid having to open the user’s defaults file each time you need a default value.

First, let’s take care of the boilerplate stuff - we want our project to have two scenes/View Controllers and the Main scene will be embedded in a Navigation Control that comes with a navigation bar which contains controls for backward and forward navigation.

The navigation controller manages transitions backward and forward through a series of view controllers. The set of view controllers managed by a particular navigation controller is called its navigation stack. The first item added to the stack becomes the root view controller and is never removed from the navigation stack. The Back button that comes with the Navigation Controller acts like the web browsers back button.


Create a new Xcode project and select a “Single View App”. Create a new Scene by dragging a new View Controller object onto your storyboard. Create a new UIViewController subclass. Go to your Project Navigator panel, right click on your your project and select a “New File…” and choose a “Cocoa Touch Class”. Call it SecondViewController.swift. Specify this new subclass as the base class for the scene you have just added to the storyboard. With the second View Controller Scene selected, show the Identity Inspector > Custom Class, select the Cocoa Touch Class you’ve just added (SecondViewController).

Add a Navigation Controller to the first scene. Select the scene by clicking on its scene dock. While the the View Controller is selected, go to the Editor menu > Select Embed In > Navigation Controller.

Select the Navigation Item from the Main View Controller Scene > Change the Title to “UserDefaults Example” and the Title for the Back Button to “Back”.

Add the Buttons, Labels and Text Field as per the screenshot below. The top Button, when clicked, will use the Segue to send the user to the second View Controller.

At this point you should run your application. When you click on the top Button, you will be sent to the Second View Controller. When you click Back you will go back to the main View Controller. We didn’t write any code yet for any of the other buttons.

In order to read and write user preferences you first need to create the UserDefaults object.

Let’s instantiate the mydefaults Object so we can set our preferences.

var mydefaults: UserDefaults = UserDefaults.standard

Now if you want to save the user’s full name you can just call:

mydefaults.set(“Don Quixote”, forKey: “UserName”)

The application automatically saves your preferences periodically to the preferences .plist file. If the application crashes before your preferences are saved they will be lost. However, you can force your application to save your preferences by calling the synchronize function.

mydefaults.synchronize()

Doing this will ensure that all your preferences that have been stored to that point have been saved.

It’s very easy to read your preferences from the preferences file.

Now that you have the UserDefaults object you can easily access the preference values that have been stored in the preferences file:

let myname = mypreferences.string(forKey: “UserName”)

What happens if there is no key/value for your preference? You either display no value or set a default value for your user preference.

You can give your UserDefaults class a dictionary of keys and values to use when no other keys/values have been provided. UserDefaults includes a method called register() that lets you specify the default values that you should have if you try to find the key/value pair that hasn’t been yet set.

let default_name = [“UserName”: “No Name”] 
//create a dictionary that contains the key/value pair
UserDefaults.standard.register(defaults: default_name)

It’s best if this statement is called early during the application startup. Add the following in the AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
 // Override point for customization after application launch.
 
 let mydefaults = [“UserName”: “No name”]
 UserDefaults.standard.register(defaults: mydefaults)

 return true
 }

For each of the three buttons (Add/Change, Retrieve and Delete) Control-drag from the Button to the ViewController.swift file and when it drops, select Action in the Connection dropdown and give it a Name, and hit Connect.

@IBAction func add_username(_ sender: Any) {}
@IBAction func retrieve_username(_ sender: Any) {}
@IBAction func delete_username(_ sender: Any) {}

We will now add code for each of the three functions above in order to add, retrieve and delete the User Name.

Let’s start first with the retrieve_username function.


 @IBAction func retrieve_username(_ sender: Any) {
 
 var strnamefound: String = ""
 
 username_found.text = UserDefaults.standard.string(forKey: "UserName")
 
 strnamefound = String(username_found.text ?? "")
 
 if (strnamefound != ""){
   username_found.text = strnamefound
 }else {
   username_found.text = "Name not found!"
 }
 }

If we run the program now, and we click on the “Retrieve User NameButton, in the username_found label it will display the default text which is the one we added in the application startup “No name” since we haven’t created a UserName Key/value pair yet.

Let’s add the required code for the other two functions:

 @IBAction func add_username(_ sender: Any) {
   UserDefaults.standard.set(username_entered.text, forKey:      
   “UserName”)
   UserDefaults.standard.synchronize()
 }

 @IBAction func delete_username(_ sender: Any) {
 
 UserDefaults.standard.set(“”, forKey: "UserName")
 
 }

Let’s now add similar code for the SecondViewController class

import UIKit

class SecondViewController: UIViewController {

 @IBOutlet weak var username_found: UILabel!
 
 override func viewDidLoad() {
   super.viewDidLoad()

   // Do any additional setup after loading the view.
 }
 
 @IBAction func find_username(_ sender: Any) {
 
   var strnamefound: String = ""
 
   strnamefound = UserDefaults.standard.string(forKey: "UserName") ?? ""
 
 if (strnamefound != ""){
     username_found.text = strnamefound
 }else {
     username_found.text = "Name not found!"
 }
 
 }
 
}

Let’s run the app now. We can add a name, retrieve the name we’ve just added or delete the name. You will notice that if we delete the name we will get the default name displayed since we don’t have the Key/Value pair in the .plist XML file anymore. If we add an empty String as the name, we will get the “Name not found!” message. Here is a screenshoot when you run the app for the first time with the default value <default_name>.



Speaking of our .plist file, here is how to find the folder where your preferences .plist file is located. Add the following code to your viewDidLoad function in your main ViewController.

let path: [AnyObject] = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true) as [AnyObject]
let folder: String = path[0] as! String
NSLog("Your NSUserDefaults are stored in this folder: %@/Preferences", folder)

Once you locate the .plist file you can open and edit it with Xcode. You will notice that if you assign nil to your key/value pair default you won’t have the UserName element under the root in your XML file. The moment you add a username (even if it’s empty) you will find the UserName element in your .plist file.

As mentioned earlier, your application will automatically write changes to the .plist preferences file at certain intervals. What happens if your application needs to exit right away? You can call the synchronize() function to force your app to save your preferences and/or refresh your scenes.

In the next blog I’ll show you how to add notification to improve this code and be able to respond to various notifications. A notification is a mechanism that various objects can use to communicate with each other. These notifications represent indications that some events have happened. More to come in my next blog.


790 views0 comments
I Sometimes Send Newsletters

Thanks for submitting!

© 2020 by Victor Balas @ devrazor.com

bottom of page