Treat Optionals with Caution in Swift

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy

Optionals are arguably the most challenging and frustrating aspect for developers that are new to Swift. What is an optional? What are the best practices for working with optionals? I explain this in detail in another post. This post zooms in on a very common error message developers run into.

unexpectedly found nil while unwrapping an optional value

The setup of this post is simple. We reproduce the error first and then explore the root cause of the problem.

Project Setup

Fire up Xcode and create a project by choosing the App template from the iOS > Application section.

Setting Up the Project in Xcode

Name the project Optionals. Set Interface to Storyboard and Language to Swift.

Setting Up the Project in Xcode

We can keep the project very, very simple. Open ViewController.swift and add an outlet with name label. The outlet is of type UILabel!, an implicitly unwrapped optional.

import UIKit

class ViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet private var label: UILabel!

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()
    }

}

In the viewDidLoad() method, we set the text property of label. This should look familiar. Right?

import UIKit

class ViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet private var label: UILabel!

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        label.text = "This is some text."
    }

}

Open Main.storyboard and add a label to the view controller scene. Select the view controller, open the Connections Inspector on the right, and connect the label to the outlet we declared a moment ago.

Setting Up the User Interface in Interface Builder

Build and run the application in the simulator. You should see a white view with a label at the center. Everything is working as expected.

Running the Application

Breaking the Application

Revisit Main.storyboard, select the view controller scene, and open the Connections Inspector on the right. Disconnect the outlet from the label. Build and run the application in the simulator. Does this look familiar.

Unexpectedly found nil while unwrapping an Optional value

It shouldn't be surprising that the application crashed. Take a look at the error. Does it make sense?

Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

A fatal error is an error the application cannot recover from. That is why the application crashed. Swift attempted to set the text property of the label property. Because we disconnected the outlet in Interface Builder, the value of label is nil. Do you see what the problem is?

Let me give you another hint. The label property is an implicitly unwrapped optional. Let's replace the exclamation mark with a question mark. We convert the implicitly unwrapped optional to an optional. This means we need to use optional chaining in viewDidLoad() to safely access the label property.

import UIKit

class ViewController: UIViewController {

    // MARK: - Properties

    @IBOutlet private var label: UILabel?

    // MARK: - View Life Cycle

    override func viewDidLoad() {
        super.viewDidLoad()

        label?.text = "This is some text."
    }

}

Build and run the application one more time. The application no longer crashes, but notice that the label isn't updated with the text we set in viewDidLoad().

Running the Application

Mind the Exclamation Mark

In Swift, an exclamation mark means danger. You should use an exclamation mark with caution and sparingly. Using the exclamation mark should always be a deliberate decision that takes the risks into account.

We declared the label property as an implicitly unwrapped optional. That is an acceptable risk and declaring outlets as implicitly unwrapped optionals is a common pattern. That said, you need to understand that you make a promise by declaring label as an implicitly unwrapped optional. You promise that label has a value by the time it is accessed. We broke that promise when we disconnected the outlet in Interface Builder.

Remember the error from earlier.

Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

The error tells us that label was equal to nil even though we promised it would have a value.

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy