Does Swift enum retain its associated value

⋅ 3 min read ⋅ Swift Enum

Table of Contents

As an iOS developer, enum with associated values is one my of my favorite language feature, and it is also a secret behind Optional, another language feature I love. I recently wonder which type of reference, strong and weak, does enum hold its associated value.

You can define Swift enumerations to store associated values of any given type, and the value types can be different for each case of the enumeration if needed.

Excerpt from Swift documentation.

I found on the Swift documentation that enumerations store the value, but it doesn't mention it is a weak or strong reference.

Weak or Strong

We can tell that enum holds a strong reference to its associated values based on the fact that Swift Optional implements using enum, and it can hold any object reference without releasing it.

Here is an example use of Swift Optional.

let user: User? = Optional.some(User()) // <1>

if let user = user { // <2>
print("It's alive")
}

<1> Enum Optional with an associated value of User().
<2> Check whether user is nil and print "It's alive" if it is not.

If the enum holds a weak reference, the User() object will get released because nobody holds it except the optional enum. We won't see anything print in the debug console. If enum holds a strong reference, we will see "It's alive" print in the console.

You should be able to guess the result without running it since we use something like this all the time. And yes, "It's alive" will be printed, which confirms that ** enum retains its associated value**.

Can we make retain cycle with an enum

Can enum cause a retain cycle? This question was popping up after I realized that enum holds a strong reference to its associated value. It definitely should, but I want to be sure, so I make a little experiment.

First, we create a LoginStatus enum. It contains two cases, guest and loggedIn with User as an associated value.

enum LoginStatus {
case loggedIn(User)
case guest
}

Then we create a User class with a LoginStatus as a property.

class User {
var status: LoginStatus = .guest

deinit {
print("deinit user") // <1>
}
}

<1> We have a deinitializer to observe whether the object gets release or not.

Experiment 1: Guest user

In this first example, I want to show that an object with no reference will be released. We create a local variable user in viewDidLoad. Run the app, and you should see "deinit user" print in the debug console. No one holds or retains our user object, so it gets released after the method ended.

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let user = User()
}
}

The result, "deinit user" printed in the console:

deinit user

Experiment 2: Logged in user

In this experiment, we want to create a retain cycle with enum. All the setups are the same as experiment 1, but this time, we set user.status to .loggedIn(user). This should create a retain cycle since the user holds a strong reference of status. And status also holds a strong reference back to user in the form of associated value in the enum, .loggedIn(user).

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

let user = User()
user.status = .loggedIn(user) // <1>
}
}

<1> We create a retain cycle by make status hold a strong reference back to user.

Run the app, and you shouldn't see any message in the debug console. The retain cycle has formed, and our user object lives happily ever after in the memory.

Conclusion

Enum holds a strong reference to its associated value is an obvious fact that I always overlook. I was never aware that I could cause retain cycle by using an enumeration. I would say it is not likely to happen in our day-to-day tasks, but you should aware that it can happen.


Read more article about Swift, Enum, or see all available topic

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 Tweet Share
Previous
Record iOS Simulator video as mp4 and GIF with Xcode

Xcode 12.5 brings many great updates and features. One of them is the ability to record a video of the app directly from the Simulator app.

Next
How to use SwiftUI Picker

Learn how to use Picker, a UIPickerView equivalent for SwiftUI.

← Home