Crashing with Swift Optionals

If you have done any iOS or Mac programming in Swift, you have probably had your app crash with the following message in Xcode’s debugger:

Fatal error: Unexpectedly found nil while unwrapping an Optional value

If you don’t understand this error message, keep reading. In this article you’ll learn what this error message means, common causes of the message, and ways to fix your code so your app stops crashing.

What Does the Message Mean?

Before I can tell you what the error message means, I need to explain Swift optionals. An optional is a data type for a variable where the variable either exists or doesn’t exist, in which case it’s nil. Pretty much anything in Swift can be an optional, including integers, strings, arrays, table views, structs, and classes. The following code shows an example of declaring an optional variable:

var description: String?

A special kind of optional is an implicitly unwrapped optional. While an optional can either exist or not exist, an implicitly unwrapped optional must exist. If an implicitly unwrapped optional is nil and you attempt to use it, the app crashes. The following code shows an example of using an implicitly unwrapped optional:

print(description!)

If description exists, the code will print the description, but if description is nil, the code crashes.

Now to answer the question in the section heading. The error message Fatal error: Unexpectedly found nil while unwrapping an Optional value is saying the app is implicitly unwrapping a nil optional value. The error is similar to accessing a nil pointer in C, C++, or Objective-C.

What Causes the Error?

The general cause of the error is having an implicitly unwrapped optional that’s nil. But you’re looking for specific causes. I can think of three common sources of implicitly unwrapped optionals that are nil.

The first common source is forgetting to connect the outlets for your user interface elements. Outlets in Interface Builder are usually declared as implicitly unwrapped optionals because you can assume the outlet is going to exist after loading the storyboard or xib file. But if you forget to connect the outlet, the outlet is nil and your app will crash when it tries to use the outlet. The following screenshot shows what a disconnected outlet looks like in Xcode:

disconnected outlet

The disconnected outlet is the circle above Line 14. A connected outlet has a filled-in circle.

The second common source is using as! to downcast to a specific type. Look at the following code to instantiate a view controller from a storyboard:

let documentViewController = storyBoard.instantiateViewController(
	withIdentifier: "DocumentViewController") 
  as! DocumentViewController

This code will crash in any of the following situations:

  • I forgot to give the view controller an identifier in the storyboard.
  • The identifier in the storyboard doesn’t match the string in the code.
  • I forgot to set the class of the view controller in the storyboard.

With implicitly unwrapped optionals it doesn’t take much to cause a crash.

The last common source is using implicitly unwrapped optionals in your code. If you see an exclamation point at the end of any of your variable names, you have a potential crash in your code. What doesn’t help matters is when you have a compiler syntax error in your code involving optionals, Xcode’s suggested fix is to make an implicitly unwrapped optional. Following Xcode’s advice makes your code more likely to crash.

How Do You Fix the Error?

The general fix to avoid these crashes is to avoid using implicitly unwrapped optionals. The following techniques will help you avoid crashes caused by implicitly unwrapped optionals:

  • Connect your user interface elements to the outlets in your code.
  • Use as? instead of as! when downcasting.
  • Use if let or guard statements to safely unwrap your optionals.
  • Use the ?? operator to provide a default value in case the optional value is nil.

To connect your user interface elements to your outlets, open Xcode’s assistant editor so your source code file and your storyboard or xib file are both open. Select the user interface element in the storyboard or xib file. Hold the Control key down and drag to the outlet in your code to make the connection.

I can demonstrate the last two techniques by fixing the earlier example of instantiating a view controller from the storyboard. Using an if let statement and as? to downcast is enough to fix the code. The following code makes sure the view controller has been instantiated, then presents the view controller:

if let documentViewController = storyBoard.instantiateViewController(
  withIdentifier: "DocumentViewController") 
  as? DocumentViewController {
    
  present(documentViewController, animated: true, completion: nil)
}

Now if I forgot to give the view controller an identifier or misspelled the name of the identifier, the app won’t crash. The app won’t present the view controller, but at least there won’t be a crash.

Get the Swift Dev Journal Newsletter

Subscribe and get exclusive articles, a free guide on moving from tutorials to making your first app, notices of sales on books, and anything I decide to add in the future.

    We won't send you spam. Unsubscribe at any time.