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.
Name the project Optionals. Set Interface to Storyboard and Language to Swift.
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.
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.
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.
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()
.
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.