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")
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
.