How to Store a Dictionary in User Defaults in Swift

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy

Storing data in the defaults database is simple thanks to the easy-to-use API of the UserDefaults class. You can take advantage of the API on iOS, tvOS, macOS, iPadOS, and watchOS. In this post, I show you how to store a dictionary in the defaults database. I promise you that it isn't rocket science.

Writing or Setting a Dictionary To User Defaults

You probably know that you can store strings, numbers, Date objects, and Data objects in the user's defaults database. Storing a dictionary is similar. There is one caveat, though. The types of the keys and values of the dictionary need to be supported by the defaults system, that is, strings, numbers, Date objects, and Data objects. Let's take a look at an example.

We access the shared defaults object through the standard class property of the UserDefaults class.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

We then create a dictionary of type [String:String] and store the dictionary in the user's defaults database by invoking the set(_:forKey:) method of the UserDefaults database. We pass the dictionary as the first argument and a key as the second argument.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

// Create and Write Dictionary
let dictionary = [
    "A": "One",
    "B": "Two",
    "C": "Three"
]

userDefaults.set(dictionary, forKey: "myKey")

This approach doesn't work if we try to store a dictionary that contains keys and/or values of an unsupported type, for example, a dictionary of type [String:URL]. Take a look at this example. We create a URL object and store it in a dictionary. The dictionary constant is of type [String:URL]. What happens if we pass the dictionary to the set(_:forKey:) method? The result is a runtime exception because URL isn't supported by the defaults system.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

// Create and Write Dictionary
let url = URL(string: "https://cocoacasts.com")!
let dictionary = [
    "A": url
]

userDefaults.set(dictionary, forKey: "myKey")

A runtime exception is thrown because URL isn't supported by the defaults system.

Reading or Getting a Dictionary From User Defaults

Reading or getting a dictionary from the user's defaults database is straightforward. The UserDefaults class doesn't define a convenience method for easily accessing a dictionary of values stored in the user's defaults database and that is why we use the object(forKey:) method. The object(forKey:) method returns an object of type Any?, an optional. In the first example, we stored a dictionary of type [String:String] in the user's defaults database. Let me show you how to retrieve that dictionary.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

// Create and Write Dictionary
let dictionary = [
    "A": "One",
    "B": "Two",
    "C": "Three"
]

userDefaults.set(dictionary, forKey: "myKey")

// Read/Get Dictionary
let strings = userDefaults.object(forKey: "myKey")

We invoke the object(forKey:) method on the shared defaults object, passing in the key of the value we are interested in, myKey in this example. Remember that object(forKey:) returns an object of type Any?. This means we need to cast the result of object(forKey:) to a dictionary of type [String:String] using the as? operator.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

// Create and Write Dictionary
let dictionary = [
    "A": "One",
    "B": "Two",
    "C": "Three"
]

userDefaults.set(dictionary, forKey: "myKey")

// Read/Get Dictionary
let strings = userDefaults.object(forKey: "myKey") as? [String:String]

The strings constant is of type [String:String]?, an optional. I strongly discourage you from using the as! operator to forced cast the result of object(forKey:) to a dictionary of type [String:String]. A runtime exception is thrown if the key that is passed to object(forKey:) doesn't exist or if the result can't be cast to a dictionary of type [String:String].

Updating or Adding a Key-Value Pair to a Dictionary In User Defaults

Updating a dictionary or adding a key-value pair to a dictionary in the user's defaults database shouldn't be difficult with what you have learned so far. We start by retrieving the dictionary from the user's defaults database. This should look familiar.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

// Read/Get Dictionary
var strings: [String:String] = userDefaults.object(forKey: "myKey") as? [String:String] ?? [:]

Notice that we use the nil-coalescing operator to default to an empty dictionary of type [String:String]. What does that mean? If the key-value pair doesn't exist, we start with an empty dictionary. It's as simple as that.

Because we want to add a key-value pair to the dictionary of strings, we define strings as a variable instead of a constant. The next step is adding a key-value pair to the dictionary.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

// Read/Get Dictionary
var strings: [String:String] = userDefaults.object(forKey: "myKey") as? [String:String] ?? [:]

// Add Key-Value Pair to Dictionary
strings["D"] = "Four"

To update the dictionary in the user's defaults database, we need to invoke the set(_:forKey:) method on the shared defaults object. We pass in the dictionary and the key we used to retrieve the dictionary.

import Foundation

// Access Shared Defaults Object
let userDefaults = UserDefaults.standard

// Read/Get Dictionary
var strings: [String:String] = userDefaults.object(forKey: "myKey") as? [String:String] ?? [:]

// Add Key-Value Pair to Dictionary
strings["D"] = "Four"

// Write/Set Dictionary
userDefaults.set(strings, forKey: "myKey")

That's it. If you need to perform this task in several places in your project, I recommend creating an extension for the UserDefaults class to make that task easier. This avoids code duplication and it also results in a cleaner API. You can read more about this technique in this post.

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy