How To Use Swift Optionals: The Ultimate Guide

Written by Reinder de Vries on May 15 2018 in App Development

How To Use Swift Optionals: The Ultimate Guide

Do you find Swift’s optionals confusing? It’s not surprising, because they can be quite tricky to grasp!

Optionals are also a powerful feature of the Swift programming language. And as an app developer, it’s important you know how to use optionals.

In this article, I’ll give you a complete tour of optionals in Swift. We’ll find out what optionals are, why they’re useful, and how you can work with them to make your code safer, bug-free and easier to maintain.

Ready? Let’s get started.

  1. What Are Optionals?
  2. How To Use Optionals
  3. How To Force Unwrap An Optional
  4. How To Use Optional Binding
  5. How To Use Optional Chaining
  6. Implicitly Unwrapped Optionals
  7. Tips & Tricks
  8. Further Reading

This article has on-page Swift Sandboxes. You can use them to try out Swift code and practice with programming, as you’re reading this article. Simply edit the code, click Run, and see the result in the output window. I encourage you to try it!

What Are Optionals?

First things first. What are optionals, and why are they useful?

You only need to know two things about optionals:

  1. Optionals can be nil or have a value
  2. You need to unwrap optionals to safely use them

On a basic level, Swift code consists of variables and functions. You use variables to store information during the execution of your Swift code. (Functions execute tasks.)

Let’s look at a situation where optionals are useful.

Consider that you’re filling out an official paper form, for instance to get a loan, at the DMV, or to sign up for an event. The form has fields for your name, your email address, and space for a photo ID of your face.

You could say that the form fields have associated Swift variables, like firstname, lastname, email and photo. The text fields are likely to be String values, and the photo field is of type UIImage.

Before you fill out the form, all fields are empty. After you’ve filled out the form, you may or may not have entered the required information for each of the fields. For instance, you might not want to provide your email address, or you object to the use of your personal photo.

You could say that the form fields are optional! They can contain a value, like your name, or no value at all.

This “no value at all” has a special notation in Swift: nil. It means “nothing” or “no value” or “empty”. But why use a special word for that? Can’t you just use an empty string?

Good question! In fact, in Objective-C, you used to have all sorts of names for values that are empty. You used NSNotFound, NSNull, NULL, or empty strings "".

And how would you indicate an empty photo? With no bitmap data? Or with a white background? Or with NULL? That’s where nil comes in.

Regardless of the type of a variable, when it’s an optional, it can be nil. It doesn’t matter whether it’s a string, an integer, a view controller, a button, an image or an object – if it’s declared as an optional, it can be nil.

Optionals go beyond forms. In an app, there are many scenarios where optionals are useful. Form fields that aren’t filled out is just one of them.

Think about a conversion from a string to integer value that may fail, and then returns nil, or a view controller outlet that hasn’t yet been connected to a class property, and is still nil.

In the last Tips & Tricks section of this article we’ll go deeper into more scenarios where optionals are useful.

Learn how to build iOS apps

Get started with iOS 12 and Swift 5

Sign up for our iOS development course Zero to App Store and learn how to build professional iOS 12 apps with Swift 5 and Xcode 10.

How To Use Optionals

You now know that you use optionals in scenarios where a value may be absent. An optional either has a value or is nil.

Here’s an example in Swift:

let name:String? = nil
print(name)

In this example, the following happens:

  • You’re creating a constant name of type String?. The question mark ?, written right after the variable type, indicates that this constant is an optional.
  • You assign nil to name, so this constant does not have a value. It’s nil!

On the last line, you print out the value of name. If you run the code, the output will be:

nil

A constant is a variable that you can’t change after it has been set. Constants are declared with the let keyword, whereas variables are declared with the var keyword.

Now what if we assign a value to name? Let’s take a look:

let name:String? = "Arthur Dent"
print(name)

Instead of nil, we now assign a string to name. It produces the following output:

Optional("Arthur Dent")

Interesting! The value is wrapped in Optional("..."), instead of just printing the value of the string literal. That’s because you need to unwrap optionals to access their values. More on unwrapping later.

You can’t assign nil to a variable or constant that’s not an optional. The following code won’t work, and will result in an error:

let score:Int = nil
print(score)

Before we continue, let’s consider that every optional is nil if it does not contain a value! Check out the following Swift code:

class Vehicle {
var wheels:Int = 4
var name:String?
}

let car = Vehicle()
print(car.wheels)
print(car.name)

car.name = "Maserati"
print(car.name)

Here’s what happens:

  • First, we’re declaring a class Vehicle with two properties: wheels of type Int, with default value 0, and name of type String?, with no default value.
  • Then, we initialize an instance of the Vehicle class and assign it to the constant car.
  • Then, we print out the value of properties wheels and name, respectively. When we run the code, we’ll see that it prints out 4 and nil. That’s because name is an optional, and it has no value. The property wheels is not an optional, so it must have a value, which is 4.
  • Finally, we change the name of car to "Maserati". At this point, the name property is still an optional, but it now has a value! When printed, its output is Optional("Maserati").

Let that sink in. See how optionals are fundamentally different from non-optionals? The key aspect of understanding how optionals work, is that they’re either nil or have a value.

How To Force Unwrap An Optional

Remember the two things you need to know about optionals?

  1. Optionals can be nil or have a value
  2. You need to unwrap optionals to safely use them

If you want to access the value of an optional variable or constant, you’ll need to unwrap it.

You can unwrap optionals in 3 different ways:

  1. With force unwrapping, using !
  2. With optional binding, using if let
  3. With implicitly unwrapped optionals, using !

A fourth approach, using optional chaining, is similar to unwrapping by letting you build a “chain” of optionals that stops executing whenever an optional in the chain is nil. More on that later.

Let’s take a look at force unwrapping. Here’s how it works:

let email:String? = "johndoe@example.com"

if email != nil {
print(email!)
}

Here’s what happens in the code:

  • First, we create a constant email of type String? and assign it a string, an email address of John Doe. The constant email is an optional, because you can see that question mark ? after String.
  • Then, using the conditional if statement, we check if email is not nil. If that’s true, so if email isn’t nil, the conditional body is executed.
  • Finally, in the conditional body, we print out the value of email. An exclamation mark ! is added right behind email. That’s force unwrapping!

You can force unwrap an optional by adding an exclamation mark to the optional constant or variable, as shown in the example above.

Now, consider the following two scenarios:

  1. Instead of having a value, email is nil
  2. You don’t use the conditional to check if email is not nil

Let’s try it out! Here’s the first scenario:

let email:String? = nil

if email != nil {
print(email!)
}

When you run the above code, the conditional expression email != nil evaluates to false. As a result, the conditional body isn’t executed. (That’s how conditionals work!)

But… what if we don’t check if email is nil and use force unwrapping anyway? Like this:

let email:String? = nil
print(email!)

When you execute that code, your app crashes and warns you about a fatal error:

Fatal error: Unexpectedly found nil while unwrapping an Optional value

That’s because you force unwrapped an optional value that’s nil! Here’s what you can take away from that:

  • Never force unwrap an optional that’s nil
  • Always check if an optional is not nil before force unwrapping it

Ultimately, force unwrapping is quick and results in more concise code, with the disadvantage of being less safe. When you force unwrap an optional without checking if it’s nil first, then you risk crashing your app.

I recommend against using force unwrapping, because the alternatives, optional binding and chaining, have greater safety and don’t introduce that much more code into your app.

Moving on!

Think of force unwrapping as unwrapping an optional “with force”. Instead of carefully looking if it might be nil, you just tear off the giftwrap with force, only to discover there’s nothing inside the giftbox. Yes, force unwrapping almost always ends in tears. BOOHOO!

How To Use Optional Binding

The alternative to force unwrapping is optional binding. Here’s how it works:

let optionalUsername:String? = "bob42"

if let username = optionalUsername {
print(username)
}

Here’s what happens:

  • First, we create a constant named optionalUsername of type String?, and assign it a string value. It’s an optional, defined with the question mark ?.
  • Then, we use optional binding to assign the value of optionalUsername to the constant username if it’s not nil. (Important!)
  • Finally, when optionalUsername is not nil, we print out the value of username.

When you run the code above, something interesting happens. Instead of printing out Optional(...), as we’ve seen before, the non-optional value of optionalUsername is printed out. How?

It’s because username is a non-optional value. It’s unwrapped by the optional binding if let statement.

What’s so special about the above code, is that the value of optionalUsername is assigned to username if optionalUsername is not nil! Try it! Change the value of optionalUsername to nil, and see if the conditional still executes. It doesn’t!

You can see optional binding as a unwrapping an optional by using a conditional and a constant.

  • When the conditional evaluates to true, i.e. when the optional is not nil, its value is assigned to the constant.
  • When the conditional evaluates to false, i.e. when the optional is nil, the conditional body is not executed.

Keep in mind that, in the code above, the username constant is only available for use within the conditional body. It’s scope is the conditional body, so you can’t use it outside of the conditional.

This is a good thing, actually. You know that you can’t declare the same variable name twice in the same scope, right? Following that rule, you can do this:

let username:String? = "bob42"

if let username = username {
    print(username)
}

You can access the global scope from within the local scope of the optional binding conditional body, and because the local username constant doesn’t reference the global (outer) username constant, you can re-use the same constant name.

I recommend against using meta-programming within variable names, so don’t call your variables optionalNumber instead of simply scores. The Swift types and syntax are there to make your code clear, concise and readable, so you don’t have to overdo that by naming variables as “definitive” or “optional”.

The biggest difference between force unwrapping and optional binding is that when you force yourself to only use optional binding, it’s impossible to accidentally unwrap an optional that’s nil. This makes your code a lot safer, and helps you to avoid those Unexpectedly found nil while unwrapping an Optional value errors.

There’s a few more things you need to know about optional binding:

  • You can combine multiple if let statements, like this:
    if  let first_name = firstnameField.text,
        let last_name  = lastnameField.text,
        let email      = emailField.text 
    {
        // Do something
    }
    
  • You can use optional binding for any optional value, so also for a function that returns an optional:
    if let score = Int("42")
    {
        print(score) 
    }
    

    In the above example, the type of Int("42") is Int?, whereas the type of score is Int. Because the conversion of string to integer might fail, its return type is an optional. Try converting Int("abc"), for instance.

  • And last but not least: you can also use var, as in if var ... = ... {. As with any variables and constants, you can change the value of a variable within the conditional body if it’s declared with var. Keep in mind that the change isn’t reflected back to the original optional, though!

We’ll get to more uses for optional binding, and combinations, in the last section of this article.

How To Use Optional Chaining

A useful approach for working with optionals is optional chaining, especially if you’re dealing with multiple optionals at once.

Let’s say you made a view controller with a text field, called usernameField, of type UITextField?. You can reference the textfield with an outlet, a property on the view controller. And you can get or set the contents of the text field with its text property. Both the usernameField property and its text property are optionals.

You could do that with optional binding, like this:

if  let field = usernameField,
    let text  = field.text {
    print("Logging in user with username: \(field.text)")
}

You could even use force unwrapping, like this:

if usernameField != nil && usernameField!.text != nil {
    print("Logging in user with username: \(usernameField!.text!)")
}

Imagine what happens when you have 10 UI components in your view controller, with optional properties, that you access in several parts of your code. It’ll quickly become a big mess of conditionals, squiggly brackets and indentations!

To avoid this so-called Pyramid of Doom, you can use optional chaining. Here’s an example:

usernameField?.text = "xoxo_darth_vader99"

The variable usernameField is an optional.See how there’s a question mark ? right after it?

At that point, one of two things happens:

  • The variable usernameField is not nil, and the call to property text succeeds
  • The variable usernameField is nil, and the call to property text fails

When the call fails, execution of that line stops gracefully. In the above example, the text property of usernameField isn’t changed when usernameField is nil.

You can chain these calls together, like this:

airplane?.wings?.left?.power = "70%"

You can use optional chaining for properties, functions and subscripts. You can also combine optional chaining with optional binding. Like this:

if let first_name = persons[indexPath.row]?.name?.first {

}

See how the above code combines a chain of optionals and optional binding? The expression persons[indexPath.row]?.name?.first returns an optional, so with optional binding you can assign the result to a constant when it’s not nil.

If you look closely, you’ll see that optional chaining and force unwrapping optionals are both sides of the same coin. Compare the following lines of code:

textField!.text = "Arthur Dent"
textField?.text = "Arthur Dent"

Both the ! and the ? deal with optionals. When textField is nil, this happens:

  • The first line, using force unwrapping, crashes
  • The second, using optional chaining, gracefully fails

Optional chaining is a seemingly insignificant, but powerful feature of Swift. As you’ll see in the last section of this article, you can combine optional chaining in a number of elegant ways.

Implicitly Unwrapped Optionals

A final use case for optionals is the implicitly unwrapped optional. It’s a bit of a tricky one, although it’s good to point out how it works for the sake of completeness.

Implicitly unwrapped optionals are optionals, so they can be nil, but you don’t have to unwrap them to access their value.

A consequence is that you need to be certain that an implicitly unwrapped optional is not nil when you access it. An implicitly unwrapped optional is like giving permission to unwrap an optional automatically every time it is used.

Implicitly unwrapped optionals can be useful for view controller outlets. Outlets are nil when a view controller is constructed, and then when the view is loaded they get assigned references to their respective user interface components.

Over the lifetime of the view controller, the outlets won’t become nil again. The benefit for the developer is that you don’t have to unwrap these optionals every time you access a user interface component in your view controller code.

You can do this by declaring the outlet property as an implicitly unwrapped optional, like this:

@IBOutlet var usernameField:UITextField!

See the exclamation mark ! after the property type? That denotes an implicitly unwrapped optional, just like a ? denotes an optional.

All is OK for now, but you’ll run in trouble with implicitly unwrapped optionals when you create a strong reference cycle between an outlet and another object.

Properties, and thus outlets, always keep a strong reference by default. If you don’t know how reference counting, strong vs. weak and memory management work, and you use implicitly unwrapped optionals with weak references to UI components, the outlet can become nil – and that’s when the trouble begins.

Because it’s an implicitly unwrapped optional, you guarantee that it’s not nil when you access it, but you’ve now broken that guarantee by trying to avoid a strong retain cycle. As a result, your outlet becomes nil, you access it, and your app crashes.

More is explained in Should Outlets Be Weak Or Strong? from CocoaCasts, or in this article from KrakenDev.

I typically recommend beginner and intermediate-level developers to avoid implicitly unwrapped optionals, because the use cases require you to know the intricate details of memory management, among other things.

It’s just as easy to use optional binding and optional chaining, and to declare outlets as weak. You can then learn about memory management and upgrade your outlets and properties to strong whenever you see fit.

As a developer, I think it’s important to work from first principles and sensible defaults. You don’t want to think about strong vs. weak every time you create an outlet, so you use the sensible default of a weak optional property.

@IBOutlet weak var usernameField:UITextField?

It’s easier to go from there to working with strong references, than it is to go from implicitly unwrapped optionals back to weak references while solving a strong reference cycle.

Tips & Tricks

Alright, let’s do a quick recap of what we’ve done so far. You now know two things about optionals:

  1. Optionals can be nil or have a value
  2. You need to unwrap optionals to safely use them

Optionals are declared with a question mark ? right after a variable type, like this:

let username:String? = "Arthur Dent"

You can unwrap optionals in three-and-a-half ways:

  1. With force unwrapping, using if [optional] != nil and [optional]!
  2. With optional binding, using if let [non-optional] = [optional] { ...
  3. With implicitly unwrapped optionals, using let [optional]:String!
  4. With optional chaining, using a?.b?.c

Let’s look at a few scenarios where practical approaches of using optionals are helpful.

Guard Let
First, you can combine optional binding and the guard statement. Like this:

func authenticate(username: String?, password:String?)
{
guard let username = username, let password = password else {
return
}

print("username = \(username), password = \(password)")
}

authenticate(username: "Bob", password: "1234")

In the above example code, you’re using guard together with let. So when either username or password is nil, the guard is invoked and the function returns early.

The constants declared in the guard statements belong to the local scope, so username and password can be used as non-optional constants in the rest of the function!

Optional Error Handling
When a function throws an error with Swift, you have to handle those errors with a do-try-catch block.

You can also “silence” errors with the try? keyword, which turns the expression into an optional, which you can then gracefully handle with optional binding.

Here, take a look at this:

enum SpeedError: Error {
case invalidSpeed
}

func setSpeed(_ speed: Int) throws
{
if speed <= 0 { throw SpeedError.invalidSpeed }
// Do things with speed
}

if let success = try? setSpeed(5) {
print("Setting speed was successful!")
}

In this comprehensive example, the function setSpeed(_:) will throw an error when the speed parameter is equal or less than 0. Because the function is marked with throws, we’ll have to handle errors with a do-try-catch block.

However, we can get around that by using try?. The expression try? setSpeed(5) now returns an optional value, so we can use that like any other optional. For instance, with optional binding.

Try it! Change the argument for setSpeed(_:) to a negative value. As a result, the conditional isn’t executed and no output is printed.

Optional Casting
When you cast a value in Swift, you’re checking the type of that value, and you can treat it as a different type within its own class hierarchy. You typically cast between subclasses and superclasses, or between related types.

Say you have an array of vehicles, of types Car and Motorbike, that both subclass a parent type Vehicle. You can then use optional binding and type casting like this:

for vehicle in garage
{
    if let car = vehicle as? Car {
        print("Vehicle with model: \(car.model), and no. passengers: \(car.passengers)")
    }
    else if let motorbike = vehicle as? Motorbike {
        print("Motorbike with model: \(motorbike.model), and is it a dirtbike: \(motorbike.dirt)")
    }
}

A key part in the above example is vehicle as? Car. When this expression fails, it will result in nil. That’s an optional! So you can use it like any other optional, for instance with optional binding.

Learn how to build iOS apps

Get started with iOS 12 and Swift 5

Sign up for our iOS development course Zero to App Store and learn how to build professional iOS 12 apps with Swift 5 and Xcode 10.

Further Reading

And that, dear developer, is how you use optionals. I hope that by now optionals are a little bit less confusing, and that you understand how this powerful Swift feature works.

Ultimately, the fact that you need to unwrap optionals forces you to consider that any particular variable or value might be nil. It’s this simple principle that makes your code safer, more bug-free, and easier to maintain, because you won’t be surprised by accidental nil values.

As a plus, optionals allow you to respond gracefully to the changing data in your app during runtime with tools such as try?, as?, and guard.

Thanks for reading this far, and if you hadn’t given those Swift Sandboxes a spin, I recommend you try them out before you go. Practice makes perfect!

Want to learn more? Check out these resources:

Enjoyed this article? Please share it!

Reinder de Vries

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.