Values and types

Swift optionals and nil

Learn how optionals and nil work in Swift, how to declare an optional with a question mark, and how to safely unwrap its value using an if let statement.

This tutorial belongs to the Swift series

Optionals are one of the key features of Swift.

Sometimes you don’t know if a value will be there. A user might not have entered a nickname. A string might not convert to a number. In Swift you express that doubt with an optional.

An optional is a box that either contains a value of some type, or contains nothing. We declare one by adding a question mark after the type:

var value: Int? = 10

Now value is not an Int. It’s an optional that wraps an Int.

Unwrapping

To use the value inside, you have to unwrap the optional. The quickest way is an exclamation mark:

var value: Int? = 10
print(value!) // 10

This is called force unwrapping, and it’s dangerous. If the box is empty, the program crashes.

Swift methods return optionals all the time. The Int initializer that accepts a string is a good example:

Swift code showing Int("37") returns Optional<Int> type when converting string to integer

It returns Int?, because Swift can’t know in advance if the string holds a number. Int("37") gives you Optional(37). Int("test") gives you nothing.

nil

nil means “no value”. An empty optional evaluates to nil, and force unwrapping it crashes:

Swift code showing Int("test") returns nil and crashes when force unwrapped with exclamation mark

The error is Fatal error: Unexpectedly found nil while unwrapping an Optional value. If you ever see it in a crash log, someone used ! on an empty optional.

You can only assign nil to an optional. A plain Int can never be nil:

Swift code showing optional variable assigned nil and comparison returning true

Swift compiler error showing nil cannot be assigned to non-optional Int type

That’s the whole point. A non-optional type is a promise that the value is always there. You never have to check it.

Unwrapping safely with if let

Instead of !, the normal way to unwrap is an if let statement:

var value: Int? = 2

if let age = value {
    print(age)
}

If value contains something, Swift puts it in the new constant age and runs the block. If it’s nil, the block is skipped. No crash possible.

Since Swift 5.7 you can shorten this when the new constant keeps the same name:

if let value {
    print(value)
}

My advice: treat ! as a warning sign. Every time you’re tempted to write it, ask what should happen when the value is missing, and write an if let instead. If a default value makes sense, the ?? operator gives it to you in one line:

let age = Int("test") ?? 0 // 0

?? is the nil-coalescing operator: it returns the value inside the optional if there is one, or the fallback on the right if there isn’t.

Lesson completed