How to save enum in UserDefaults using Swift

⋅ 3 min read ⋅ Swift UserDefaults Enum

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.

  1. Enumerations with raw value (or can easily assign a raw value).
  2. 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.

Sponsor sarunw.com and reach thousands of iOS developers.

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.

  1. We give enum a raw type that is supported by UserDefaults, e.g., integer or string.
  2. 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

  1. Specifying the raw type as the first item in the enumeration's type inheritance list, .e.g, enum Frequency: Int
  2. 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.


  1. 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 Share
Previous
Responsive 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.

Next
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.

← Home