Interacting with the defaults system is easy thanks to the UserDefaults
class. You can store a range of data types in the user's defaults database, including strings, numbers and Date
objects. The UserDefaults
class is available on iOS, tvOS, macOS, iPadOS, watchOS and Mac Catalyst.
The UserDefaults
class has a rich API, but how do you check if a value exists in the user's defaults database in Swift? There are a few options and I show you an elegant, easy-to-understand solution in this post.
Some Caveats
Let's start with an example. We store a key-value pair in the user's defaults database. The value is a boolean, true
, and the key is a string, myKey
.
import Foundation
// Write/Set Boolean in User Defaults
UserDefaults.standard.set(true, forKey: "myKey")
Reading the value for the key is easy by invoking the bool(forKey:)
method of the UserDefaults
class.
import Foundation
// Write/Set Boolean in User Defaults
UserDefaults.standard.set(true, forKey: "myKey")
// Read/Get Boolean from User Defaults
UserDefaults.standard.bool(forKey: "myKey")
It's important to know that bool(forKey:)
returns false
if no value is set for the specified key. In other words, if you need to know if a value exists for the specified key, then bool(forKey:)
won't help you.
Asking for the Object
The solution is surprisingly simple, though. Instead of asking for the boolean, we ask for the object. This means that we invoke object(forKey:)
instead of bool(forKey:)
. The object(forKey:)
method returns an object of type Any?
, an optional. If the key-value pair doesn't exist, object(forKey:)
returns nil
. Let's try it out. I have updated the previous example to make it more readable and the print statements should make the example easier to understand.
import Foundation
// Helpers
let key = "myKey"
let userDefaults = UserDefaults.standard
// Remove Key-Value Pair
userDefaults.removeObject(forKey: key)
// Before Setting Boolean
print("before", userDefaults.bool(forKey: key))
print("before", userDefaults.object(forKey: key) == nil)
// Write/Set Boolean in User Defaults
userDefaults.set(true, forKey: key)
// After Setting Boolean
print("after", userDefaults.bool(forKey: key))
print("after", userDefaults.object(forKey: key) == nil)
Let me walk you through the code snippet. We add an import statement for the Foundation framework because the UserDefaults
class is defined in Foundation. To avoid code duplication and typos, we store the key in a constant with name key
and keep a reference to the shared defaults object in a constant with name userDefaults
.
import Foundation
// Helpers
let key = "myKey"
let userDefaults = UserDefaults.standard
To be sure, we remove the value for the key myKey
. This removes the key-value pair.
// Remove Key-Value Pair
userDefaults.removeObject(forKey: key)
Before we set the boolean for the key myKey
we print the return value of the bool(forKey:)
method. We also ask the shared defaults object for the object for the key myKey
and check if the return value is equal to nil
. If object(forKey:)
returns nil
, then we know that the key-value pair doesn't exist.
// Before Setting Boolean
print("before", userDefaults.bool(forKey: key))
print("before", userDefaults.object(forKey: key) == nil)
We then set the boolean for the key myKey
and repeat the print statements.
// Write/Set Boolean in User Defaults
userDefaults.set(true, forKey: key)
// After Setting Boolean
print("after", userDefaults.bool(forKey: key))
print("after", userDefaults.object(forKey: key) == nil)
If you run this code snippet in a playground, you should see the following output in the console.
before false
before true
after true
after false
The bool(forKey:)
method returns the boolean for the given key. If the key-value pair doesn't exist, bool(forKey:)
returns false
. This isn't true for the object(forKey:)
method. It returns nil
if the key-value pair doesn't exist.
Creating an Extension for User Defaults
Let's create an extension for the UserDefaults
class to make checking the existence of a key-value pair easier and more elegant. We create an extension for the UserDefaults
class below the import statement for the Foundation framework and define a method with name valueExists(forKey:)
. The return value is of type Bool
.
import Foundation
extension UserDefaults {
func valueExists(forKey key: String) -> Bool {
}
}
In valueExists(forKey:)
, we ask the UserDefaults
object for the object for the specified key. If the result isn't equal to nil
, the method returns true
. If the result is equal to nil
, the method returns false
.
import Foundation
extension UserDefaults {
func valueExists(forKey key: String) -> Bool {
return object(forKey: key) != nil
}
}
Let's put the valueExists(forKey:)
method to use by updating the previous example. We update the print statements by taking advantage of the valueExists(forKey:)
method.
import Foundation
extension UserDefaults {
func valueExists(forKey key: String) -> Bool {
return object(forKey: key) != nil
}
}
// Helpers
let key = "myKey"
let userDefaults = UserDefaults.standard
// Remove Key-Value Pair
userDefaults.removeObject(forKey: key)
// Before Setting Boolean
print("before", userDefaults.valueExists(forKey: key))
// Write/Set Boolean in User Defaults
userDefaults.set(true, forKey: key)
// After Setting Boolean
print("after", userDefaults.valueExists(forKey: key))
Run the contents of the playground one more time to see the result.
before false
after true
We implemented a simple extension for the UserDefaults
class with a single method. With little effort, we extended the API of the UserDefaults
class with a very useful method. That is why I often use an extension for the UserDefaults
class. I explain this technique in another post.