Setting And Getting Data With UserDefaults In Swift

Written by Reinder de Vries on September 19 2017 in App Development

How To Setting And Getting Data With UserDefaults In Swift

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 article you’ll learn:

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

Ready? Let’s go.

  1. What Are UserDefaults?
  2. Saving Data in UserDefaults
  3. Getting Data from UserDefaults
  4. When to Use UserDefaults
  5. Further Reading

What Are UserDefaults?

So what are these UserDefaults?

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

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

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

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

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? User defaults 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 column-row format, like this:

The dictionary structure is still 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!

Note: 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.

Learn how to build iOS apps

Get started with iOS 12 and Swift 4

Sign up for our iOS development course Zero to App Store and learn how to build professional iOS 12 apps with Swift 4 and Xcode 10.

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 the Objective-C framework Foundation.

Before you can save data in the user defaults you need to grab a reference to the 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.

So, 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…

Learn how to code your own iOS apps by mastering Swift 4 and Xcode 10 » Find out how

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 variable:

let defaults    = NSUserDefaults.standard
let name        = defaults.string(forKey: "name") ?? "Unknown user"
let occupation  = defaults.string(forKey: "occupation") ?? "Unknown"
let age         = defaults.int(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. The one function that can return values for any type is object(forKey:), which will return values with the type Any?.

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 always 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 information. The app’s language is saved in the iPhone’s locale settings.

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.

Learn how to build iOS apps

Get started with iOS 12 and Swift 4

Sign up for our iOS development course Zero to App Store and learn how to build professional iOS 12 apps with Swift 4 and Xcode 10.

Further Reading

So, 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. Always investigate what database to use for your specific use case.

Want to learn more? Check out these resources:

Do you have questions about UserDefaults? Let me know in the comments, below!

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.

Leave a Reply

Required to post: Your real name and email address, and a pleasant demeanor. Your email address will not be published. Markdown is supported.

  • Pavel Sorokin September 3, 2018 13:53

    "Whenever you’ve changed the user defaults you need to synchronize them, to make the changes persist on the disk." -- this is a terrible advice! The official Apple docs for #synchronize say: " this method is unnecessary and shouldn't be used." Sadly, a lot of guides and SO answers still recommend this without any apparent reason. Using this method, at least since iOS 11 (and your article is written the day iOS 11 went live), is just an anti-pattern.

    1. Reinder de Vries September 3, 2018 14:11 in reply to Pavel

      Thanks for bringing this to my attention, Pavel! I've updated the article. I read that the synchronize() will be deprecated in the future, so I suppose more people will learn about it. Old habits die hard – you used to have to call synchronize(), but you're right: that's a long time ago ;-)

  • Tummy Guns June 4, 2018 12:14

    can i use one application setting bundle data to another app ??? if it is posible then please send me how to get data And advance thnks

    1. Reinder de Vries June 4, 2018 13:32 in reply to Tummy

      When both apps are part of the same App Group, they can share the same UserDefaults, as explained here. You can also use this for App Extensions, i.e. Today widgets. You can't share user defaults between apps that aren't in the same App Group. And you can't group together apps that you didn't develop, of course.

  • Hi Reinder! Thanks so much for the information, it helped a lot! I'm still struggling with saving the checkmark state in my tableview cells. What is the best way to go about this?

    1. Reinder de Vries January 16, 2018 10:46 in reply to Kristina

      Awesome! Glad you like it, Kristina. As for saving the state of table view cells, I think you should use a database for that. So every cell has an associated database entry, and gets the data from the database when it's shown on screen. It's a bit more involved of course ;-) I find that Realm (a database framework) is easiest to use. Many of my intermediate-level courses use databases, so I recommend you check those out!

  • Really great explanation thanks for your time, I am trying to save an image with UserDefaults, do you have any tutorials on that subject?
    Thanks again for your time and commitment.

    1. Reinder de Vries December 26, 2017 23:01 in reply to Drewgost

      Thanks! Glad I can help :-)

      You can save a Data (NSData class in ObjC) object in UserDefaults. You can get the Data from a UIImage, see "Accessing the Image Data" here: https://developer.apple.com/documentation/uikit/uiimage This essentially creates a JPEG (or PNG) and stores that data in a Data object.

      By the way, if you want to store more than one image I recommend saving the image to disk as a file. You want to avoid saving too much data in the UserDefaults. I don't have any tutorials on the subject, but I'll add it to the list! In the meantime, here's a good article: https://www.hackingwithswift.com/example-code/media/how-to-save-a-uiimage-to-a-file-using-uiimagepngrepresentation

      1. Drewgost December 27, 2017 00:00 in reply to Reinder

        Thanks again