DEV Community

Monica Granbois
Monica Granbois

Posted on • Originally published at monicagranbois.com

1 2

The reason for implicitly unwrapped optionals

In a previous post, I wrote about implicitly unwrapped optionals. However, I was not happy with the example I created; it felt contrived. The following is the example I used:

let myMailBox = MailBox()
myMailBox.mail = Mail(to: "Alice", from: "Bob")

let myMailImplicitlyUnwrapped: Mail! = myMailBox.mail

print(myMailImplicitlyUnwrapped.to) // the ! is not needed
print(myMailImplicitlyUnwrapped.from)
Enter fullscreen mode Exit fullscreen mode

This code did not seem realistic. It left me with several questions. When would I create code like this? In what scenario would I create the myMailImplicitlyUnwrapped constant? Why wouldn’t I assign Mail(to: "Alice", from: "Bob") to the constant instead. Example:

let myMail: Mail =  Mail(to: "Alice", from: "Bob") 
print(myMail.to) 
print(myMail.from)
Enter fullscreen mode Exit fullscreen mode

I wanted to understand more about implicitly unwrapped optionals. Where are they used and what is their purpose?

After some research I found two use case scenarios:

  • declaring an @IBOutlet
  • avoiding reference cycles

In both cases, their purpose is to create simpler code.

@IBOutlet

Declaring an @IBOutlet appears to be the main use case. From Start Developing iOS Apps (Swift):

When a view controller is loaded from a storyboard, the system instantiates the view hierarchy and assigns the appropriate values to all the view controller’s outlets. By the time the view controller’s viewDidLoad() method is called, the system has assigned valid values to all of the controller’s outlets, and you can safely access their contents.

Since the outlet will be set after initialization we want to use it as a non-optional property. If the outlet were an optional, then any code using it would first need to unwrap it. Declaring the outlet as an implicitly unwrapped optional means any calling code can access it directly. This leads to simpler code.

Avoiding reference cycles

A reference cycle is when two classes contain references to each other. A memory leak can occur if the classes contain strong references to each other. The leak occurs because ARC is unable to remove the classes from memory, even when they are no longer in use. This is because each class has a property that references the other class.

There are several ways to create reference cycles and each has their own solution. One scenario to consider is where neither property can be nil after initialization. The Swift documentation describes the situation:

However, there is a third scenario, in which both properties should always have a value, and neither property should ever be nil once initialization is complete. In this scenario, it’s useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.

This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle.

Example from Apple's documentation:

class Country {
    let name: String
    var capitalCity: City!
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

Enter fullscreen mode Exit fullscreen mode

Declaring capitalCity as an implicitly unwrapped optional means it is initially nil. The nil value allows the Country class to initialize and pass self to the City initializer. After Country and City are initialized, capitalCity will have a non-nil value. Now, any code using capitalCity can access it directly. If capitalCity were an optional, it would need to be unwrapped when used. But as an implicitly unwrapped optional, this is not needed. So, again the implicitly unwrapped optional makes the code simpler to work with.

Thank you for reading! If I missed a case for implicitly unwrapped optionals, please let me know!

References

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

The Most Contextual AI Development Assistant

Pieces.app image

Our centralized storage agent works on-device, unifying various developer tools to proactively capture and enrich useful materials, streamline collaboration, and solve complex problems through a contextual understanding of your unique workflow.

👥 Ideal for solo developers, teams, and cross-company projects

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay