How to save enum in UserDefaults using Swift
Table of Contents
The UserDefaults is a database for storing small key-value pairs.
The value that means to be stored in the UserDefaults
is the user's preferences. The UserDefaults
class provides an interface for interacting with the defaults system[1]. The defaults system allows an app to customize its behavior to match a user's preferences, hence the name - UserDefaults
.
The problem
The problem is only String
, Data
, Number
, Date
, Array
, and Dictionary
are supported. Enumerations, which is a type that I think is perfect for representing options for users isn't supported.
Luckily the solution to this problem is easy.
I will provide a solution based on the type of enumerations.
- Enumerations with raw value (or can easily assign a raw value).
- Enumerations with associated value
In this article, we will explore the simpler case first, enumerations with raw value. We will talk about enumerations with associated value in the next article.
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
How to save enum in UserDefaults
For demonstration, we create a Frequency
enum for users to choose how often they want to receive a notification.
enum Frequency {
case daily
case weekly
case monthly
}
If we save this enum to UserDefaults, you will get a runtime exception.
UserDefaults.standard.set(
Frequency.daily,
forKey: "frequency")
// Attempt to insert non-property list object example_enum_userdefaults.Frequency.daily for key frequency
The solution for this is easy.
- We give enum a raw type that is supported by
UserDefaults
, e.g., integer or string. - We read and write with its raw value.
Enumerations with Raw Values
Enumeration cases can come prepopulated with default values (called raw values).
You give enum a raw value type by
- Specifying the raw type as the first item in the enumeration's type inheritance list, .e.g,
enum Frequency: Int
- Assign a raw value to cases with an assignment operator (
=
).
In this case, I specify the number of days as its raw value.
enum Frequency: Int {
case daily = 1
case weekly = 7
case monthly = 30
}
Read and write enumerations by their raw value
Our enum is now representable by integer type, which is supported by UserDefaults
. We can read and write them to UserDefaults
by their raw value.
To save enumerations, you save its raw value to UserDefault
. You can access a raw value by the rawValue
property.
UserDefaults.standard.set(
Frequency.daily.rawValue,
forKey: "frequency")
To retrieve the value, we get its raw value back and initialize our enum with that raw value.
let userDefaults = UserDefaults.standard
userDefaults.set(
Frequency.weekly.rawValue,
forKey: "frequency")
// 1
let rawValue = userDefaults.integer(forKey: "frequency")
print(rawValue)
// 7
// 2
let frequency = Frequency(rawValue: rawValue)
print(frequency)
// Optional(example_enum_userdefaults.Frequency.weekly)
1 Get a raw value back from UserDefaults.
2 Initialize our enum with that raw value.
Caveats
One thing I want to highlight here is if you modify the raw value, there is a chance that init?(rawValue:)
will be failed because Int
values retrieved don't correspond to a case of Frequency
.
If you save Frequency.monthly
in the first version of your app and you change its raw value to 31
in version two, the frequency you retrieve back will be nil
.
let userDefaults = UserDefaults.standard
userDefaults.set(
Frequency.monthly.rawValue,
forKey: "frequency")
Set raw value of 30
to UserDefaults.
Then, you decided to change the raw value of the .monthly
case to 31
.
enum Frequency: Int {
case daily = 1
case weekly = 7
// 1
case monthly = 31
}
// 2
let rawValue = userDefaults.integer(forKey: "frequency")
print(rawValue)
// 30
// 3
let frequency = Frequency(rawValue: rawValue)
print(frequency)
// nil
1 Decided to change raw value for monthly
to 31
.
2 The value returned here is 30
.
3 There is no Frequency with a raw value equal to 30
anymore, resulting in failed initializing.
The user defaults system manages the storage of preferences for each user. Most preferences are stored persistently and therefore do not change between subsequent launch cycles of your app. Apps use preferences to track user-initiated and program-initiated configuration changes. ↩︎
Read more article about Swift, UserDefaults, Enum, or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareResponsive layout in SwiftUI with ViewThatFit
Making SwiftUI views responsive usually involves a lot of GeometryReaders and if-else. In iOS 16, SwiftUI got a new view that makes it easier. Let's learn how to do it.
Custom Layout in SwiftUI
If you have a layout that the built-in layout like VStack and HStack can't serve, you can create a custom one in iOS 16. Let's learn how to do it.