How to Store an Array 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 an array in the defaults database. I promise you that it isn't rocket science.

Writing or Setting an Array To User Defaults

You probably know that you can store strings, numbers, Date objects, and Data objects in the user's defaults database. Storing an array is similar. There is one caveat, though. You can only store arrays of strings, numbers, Date objects, and Data objects in the user's defaults database. 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 an array of strings and store the array in the user's defaults database by invoking the set(_:forKey:) method of the UserDefaults database. We pass the array of strings as the first argument and a key as the second argument.

import Foundation

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

// Create and Write Array of Strings
let array = ["One", "Two", "Three"]
userDefaults.set(array, forKey: "myKey")

This approach doesn't work if we try to store an array of an unsupported type, for example, an array of URL objects. Take a look at this example. We create a URL object and store it in an array. The array constant is of type [URL]. What happens if we pass the array 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 Array of URLs
let url = URL(string: "https://cocoacasts.com")!
userDefaults.set([url], forKey: "myKey")

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

Reading or Getting an Array From User Defaults

Reading or getting an array from the user's defaults database is straightforward. The UserDefaults class doesn't define a convenience method for easily accessing an array 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 an array of String objects in the user's defaults database. Let me show you how to retrieve that array of strings.

import Foundation

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

// Create and Write Array of Strings
let array = ["One", "Two", "Three"]
userDefaults.set(array, forKey: "myKey")

// Read/Get Array of Strings
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 an array of String objects using the as? operator.

import Foundation

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

// Create and Write Array of Strings
let array = ["One", "Two", "Three"]
userDefaults.set(array, forKey: "myKey")

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

The strings constant is of type [String]?, an optional. I strongly discourage you from using the as! operator to forced cast the result of object(forKey:) to an array of strings. 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 an array of String objects.

Updating or Appending a Value to an Array In User Defaults

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

import Foundation

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

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

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

Because we want to append a value to the array of strings, we define strings as a variable instead of a constant. The next step is appending a string to the array of strings.

import Foundation

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

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

// Append String to Array of Strings
strings.append("Four")

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

import Foundation

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

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

// Append String to Array of Strings
strings.append("Four")

// Write/Set Array of Strings
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.

A Convenience Method for Strings

The UserDefaults class defines one convenience method for reading or getting an array of objects, more specifically an array of String objects. The stringArray(forKey:) method returns a value of type [String]?, an optional array of String objects. We can simplify the previous example using this convenience method.

import Foundation

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

// Read/Get Array of Strings
var strings: [String] = userDefaults.stringArray(forKey: "myKey") ?? []

// Append String to Array of Strings
strings.append("Four")

// Write/Set Array of Strings
userDefaults.set(strings, forKey: "myKey")

We can omit the as? operator because the convenience method returns a value of type [String]?. We still need the nil-coalescing operator to default to an empty array of String objects if stringArray(forKey:) returns nil.

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