Back to blog

Working with UserDefaults in Swift


Aasif Khan
By Aasif Khan | Last Updated on July 20th, 2023 4:07 pm | 5-min read

The UserDefaults object, formerly known as NSUserDefaults, is exceptionally useful for storing small pieces of data in your app. You use it to save your app user’s settings, set some “flags”, or simply use it as a tiny data store.

In this app development tutorial you’ll learn:

  • How to set and get data with UserDefaults
  • When it’s best to use UserDefaults (and when not…)
  • How to work with user defaults to improve your iOS development

What are UserDefaults?

So what are these UserDefaults?

The user defaults is a .plist file in your app’s package. You use it to set and get simple pieces of data. It’s structure is similar to that of a dictionary and the user defaults are often regarded as a key-value store.

A key-value store (“KVS”) is, as the name says, a way to assign values to certain keys. Like this:

var dict = [
“name”: “John Doe”,
“language”: “English”,
“occupation”: “Carpenter”
]

It’s a dictionary. On the left you see keys, and on the right you see values. When you want to get to John’s name, you simply do:

print(dict[“name”])
// Output: John Doe

When you want to change John’s occupation, you simply do:

dict[“occupation”] = “Engineer”
Quite simple, right? Working with the UserDefault class is not much different.

Internally, the user defaults are saved in a .plist file. A property list file (hence, “plist”) is a dictionary saved in a row-column format, like this:

The dictionary structure is clearly visible: you see keys on the left, and values on the right. The most common .plist file in any app is of course the Info.plist, that contains many basic settings of your app, like it’s name and Bundle ID.

When you check out the documentation for the UserDefaults class you’ll see that the class has several important functions:

  • init() function and standard property for initializing the user defaults
  • object(forKey:), url(forKey:), string(forKey:), bool(forKey:) etc. for getting values from the defaults
  • set(_:forKey:) for storing values in the user defaults, and removeObject(forKey:) to remove them

In the next chapters you’ll check out all of these functions. Let’s continue!

Quick Note: Before Swift 3, the UserDefaults class was known as NSUserDefaults. Swift 3 removed many of these “NS” prefixes.

Why are they called “user defaults”? Although it’s not official, I’ve always regarded the user defaults as “the default settings, configurations and data an app user starts the app with”. It’s kind of a little set of data that’s available right from the start of the app, that you use to store simple and general config info.

Saving Data in UserDefaults

Let’s first look at saving data in the user defaults. You can save a number of simple variable types in the user defaults:

  • Booleans with Bool, integers with Int, floats with Float and doubles with Double
  • Strings with String, binary data with Data, dates with Date, URLs with the URL type
  • Collection types with Array and Dictionary

Internally the UserDefaults class can only store NSData, NSString, NSNumber, NSDate, NSArray and NSDictionary classes. These are object types that can be saved in a property list. You can also tell by the “NS” prefix that they are part of a Objective-C framework.

Before you can save data in the user defaults you need to grab a reference to the standard user defaults. In most cases you can work with the standard property like this:

UserDefaults.standard

In the example above, you use the class variable standard, which is available anywhere in your code, to get hold of the “standard user defaults”.

You can also create your own user defaults, called a persistent domain, which you can read more about in the documentation.

When you want to save something, you simply do this:

let name = “John Doe”
UserDefaults.standard.set(name, forKey: “name”)
In the above example you’re assigning the variable name to the key “name” in the user defaults, effectively creating this key-value pair:

{
“name”: “John Doe”
}

As you’ve seen in the official documentation, that set(_:forKey:) takes a number of types as its first argument, as long as they can be saved in a property list file.

Quick Tip:

Do you want to save one of your own object types, like Vehicle or Person? Make sure to adopt the NSCoding protocol, then encode your object to a Data object, save it in the user defaults, and then decode it again when you need it later on. Also, always check if this is data you really want to store in the user defaults…

Then, when you want to remove that value from the user defaults you simply call:

UserDefaults.standard.removeObject(forKey: “name”)

You can also overwrite an object that you’ve previously set:

UserDefaults.standard.set(“Arthur Dent”, forKey: “name”)

The user defaults are cached in the iPhone’s memory and they remain there when your app is running. The user defaults are automatically persisted to the disk (asynchronously), so it’s not necessary to manually save or synchronize the user defaults.

Now that you’ve saved your values, let’s see how you can get them back…

Getting Data from UserDefaults

Getting data from the user defaults is just as simple as saving it. Here’s how you get the value associated with the key “name”:

let name = NSUserDefaults.standard.string(forKey: “name”)
print(name)
// Outputs: Arthur Dent
It’s worth noting here that these getters will return optional values, so the type of name is String?. When the “name” key doesn’t exist, the above code returns nil.

It then makes sense to use optional binding to get the value safely:

if let name = NSUserDefaults.standard.string(forKey: “name”) {
print(name)
}

You can also use the nil-coalescing operator ?? to provide a default value:

let name = NSUserDefaults.standard.string(forKey: “name”) ?? “Unknown user”

Just like with saving the user defaults, you can save yourself some time typing, and make your code clearer, if you assign the standard user defaults to a temporary local constant:

let defaults = NSUserDefaults.standard
let name = defaults.string(forKey: “name”) ?? “Unknown user”
let occupation = defaults.string(forKey: “occupation”) ?? “Unknown”
let age = defaults.integer(forKey: “age”) ?? 0

You may have noticed that the functions you use to get values from the user defaults can return values with an explicit type, such as string(forKey:). The one function that can return values for any type is object(forKey:), which will return values with the type Any?, which you can type cast.

These functions are url(forKey:), array(forKey:), dictionary(forKey:), string(forKey:), stringArray(forKey:) (with type [String]?), data(forKey:), bool(forKey:), integer(forKey:), float(forKey:), and double(forKey:).

Logically, when you’re retrieving a value as Int, but it’s stored as a String, the returned value is nil.

So… when do you actually need to use the user defaults?

When to Use UserDefaults

The user defaults are best used for simple pieces of data. If you need to store multiple objects of the same type it’s smarter to use an actual database, like Realm. Database design is an important aspect of the architecture of your app.

Good use cases for UserDefaults are:

  • User information, like name, email address, age, occupation
  • App settings, like user interface language, app color theme or “detailed vs. simple UI”
  • Flags, more on this later

It’s important to check whether a data point can, or should be, saved somewhere else. Many back-end frameworks, for instance, already have storage in place to save a current user’s login information. The app’s language is saved in the iPhone’s locale settings, for example.

One smart way to use user defaults are flags. They are boolean values (true or false) that indicate whether some event or setting has already happened. Examples:

  • If the user already has completed the app’s onboarding, with “hasOnboarded”
  • If the user has already upgraded the in-app database, with “databaseUpgraded”
  • If the user is one of your app’s initial beta testers, and should get an upgrade for free, with “isBetaTester_2013”

You can also use flags for more complex data points, like dates:

  • When the user last updated the app, and you can then show a message to update the app to a better supported version
  • When the last cloud sync date was, and sync when the gap is too big
  • When the last time the user was asked for feedback on the app

It’s always important to think through the possible scenarios when working with flags, because it’s easy to make mistakes. One way of keeping track is to create a simple flow diagram showing the different flags, states and defaults you’re using in your app. You can then easily spot if your app can get to an unsupported state, and then change your code accordingly.

Important: Don’t use UserDefaults for personal or sensitive data. The user defaults are a simple .plist file in the app package, so it’s fairly easy to get the data out and change it. Store one-time passwords, UUIDs, IAP data and even high-score data in the iOS keychain.

Further Reading

That’s all there is to setting and getting data with UserDefaults! It’s a small, neat data store you can use to save simple settings. Here’s what we discussed:

  • What UserDefaults are and why they’re useful
  • How to set and get data with UserDefaults in Swift
  • Smart use cases for UserDefaults, and when not to use it

Aasif Khan

Head of SEO at Appy Pie

App Builder

Most Popular Posts