The UserDefaults
class has a fairly extensive API that should meet most of your needs. From time to time, however, you need to perform a task that is less trivial. How do you clear the user's defaults database? The UserDefaults
class doesn't offer this functionality. What options do you have to reset the user's defaults database in Swift?
Reset Standard User Defaults
The documentation of the UserDefaults
class lists a method in the Legacy section that seems to do the trick. The method is named resetStandardUserDefaults()
. Don't get your hopes up, though. The description of the method says "This method has no effect and shouldn't be used." Let's put that to the test. Create a playground, add the following code snippet, and run the contents of the playground.
import Foundation
// Write/Set Boolean in User Defaults
UserDefaults.standard.set(true, forKey: "myKey")
// Before Resetting User Defaults
print("before", UserDefaults.standard.bool(forKey: "myKey"))
// Reset Standard User Defaults
UserDefaults.resetStandardUserDefaults()
// After Resetting User Defaults
print("after", UserDefaults.standard.bool(forKey: "myKey"))
The output in the console confirms that the resetStandardUserDefaults()
method has no effect. It doesn't clear or reset the user's defaults database.
before true
after true
Removing a Key-Value Pair
To remove a key-value pair from the user's defaults database, you need to invoke removeObject(forKey:)
on the UserDefaults
instance. Let's update the previous example.
import Foundation
// Write/Set Boolean in User Defaults
UserDefaults.standard.set(true, forKey: "myKey")
// Before Resetting User Defaults
print("before", UserDefaults.standard.bool(forKey: "myKey"))
// Remove Key-Value Pair
UserDefaults.standard.removeObject(forKey: "myKey")
// After Resetting User Defaults
print("after", UserDefaults.standard.bool(forKey: "myKey"))
The output in the console confirms that the removeObject(forKey:)
method works as advertised.
before true
after false
Removing Every Key-Value Pair
The removeObject(forKey:)
method also works fine if you need to remove multiple key-value pairs. For that to work, you need to carefully keep track of the data you store in the user's defaults database. There are several solutions to accomplish this. Let's take a look at one of them.
We start by defining an extension for the UserDefaults
class. In the extension, we create a enum with name Keys
and String
as the raw value. The Keys
enum manages the keys used to store data in the user's defaults database.
import Foundation
extension UserDefaults {
enum Keys: String {
case unitsNotation
case temperatureNotation
case allowDownloadsOverCellular
}
}
We conform the Keys
enum to the CaseIterable
protocol. Why is this necessary? If we conform the Keys
enum to the CaseIterable
protocol, a computed property with name allCases
automatically becomes available. This computed property returns an array that includes every case the Keys
enum defines. This comes in useful in a few moments.
import Foundation
extension UserDefaults {
enum Keys: String, CaseIterable {
case unitsNotation
case temperatureNotation
case allowDownloadsOverCellular
}
}
With the Keys
enum in place, we can implement an instance method with name reset()
. The implementation requires a single line of code. We ask the Keys
enum for the array of cases using the allCases
computed property. We use the forEach(_:)
method to loop over the array of cases. We invoke the removeObject(forKey:)
method on the UserDefaults
instance, passing in the raw value of the case. That's it.
import Foundation
extension UserDefaults {
enum Keys: String, CaseIterable {
case unitsNotation
case temperatureNotation
case allowDownloadsOverCellular
}
func reset() {
Keys.allCases.forEach { removeObject(forKey: $0.rawValue) }
}
}
It goes without saying that this solution only works if you diligently use the Keys
enum in the rest of the project. Let's take a look at an example.
import Foundation
extension UserDefaults {
enum Keys: String, CaseIterable {
case unitsNotation
case temperatureNotation
case allowDownloadsOverCellular
}
func reset() {
Keys.allCases.forEach { removeObject(forKey: $0.rawValue) }
}
}
// Write/Set Boolean in User Defaults
UserDefaults.standard.set(true, forKey: UserDefaults.Keys.allowDownloadsOverCellular.rawValue)
print("before", UserDefaults.standard.bool(forKey: UserDefaults.Keys.allowDownloadsOverCellular.rawValue))
// Reset User Defaults
UserDefaults.standard.reset()
print("after", UserDefaults.standard.bool(forKey: UserDefaults.Keys.allowDownloadsOverCellular.rawValue))
Run the contents of the playground and inspect the output in the console. We use the Keys
enum to set the value of the allowDownloadsOverCellular
key to true
. The first print statement confirms that this works. We then invoke the reset()
method to clear the user's defaults database. The second print statement confirms that the reset()
method works as expected.
before true
after false
Room for Improvement
We could further improve the solution by adding convenience properties for each of the settings, but that is beyond the scope of this post. You can read more about that technique in another post.