Back to blog

Optionals in Swift: The Ultimate Guide


Aasif Khan
By Aasif Khan | December 9, 2021 3:07 pm  | 6-min read

In Swift, optionals are nil or have a value. Before you can use an optional, you’ll need to unwrap it. Optionals are a powerful feature of the Swift programming language, because they make your code safer and more productive. And as an iOS developer, it’s important you know how to use optionals.

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

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

What Are Optionals?

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 fundamental level, Swift code consists of variables and functions. You use variables to store information while your Swift code runs; and functions execute clearly defined tasks in your code.

How do optionals fit in? Let’s look at a scenario where they are useful.

Consider that you’re filling out an official paper form, for example to get a loan, or a gym membership, or to sign up for a Swift conference. The signup 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 values of type String, 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 example, 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, way back when, with Objective-C, you used to have all sorts of names for values that were empty. You used NSNotFound, NSNull, NULL, or empty strings “”.

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

If a variable contains no value, it is nil, regardless of the type of the variable, and provided it’s declared as an optional. 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 they’re useful. Form fields that aren’t filled out is just one of them. A few examples:

  • A conversion from a string, like “123”, to an integer 123, which may fail, such as for string “X12”, which can’t be converted to an integer and thus returns nil
  • A view controller outlet property, which is nil before the view controller has been loaded property. Until it’s loaded, you can’t use it.
  • Properties of a struct that are nil until values from a back-end webservice or database have been retrieved

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

How To Use Optionals

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

Here’s an example in Swift:

let name:String? = nil
print(name)

Here’s what happens in the above example:

  • On the first line, you’re creating a constant name of type String?.
  • The question mark ?, written right after the type annotation, indicates that this constant is an optional.
  • You assign nil to name, so this constant does not have a value. It’s nil. We say that name “is an optional”.
  • On the last line, you print out the value of name.

When you run the code, the output is:

nil

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

let name:String? = “Arthur Dent”
print(name)

The type of name stays the same, so it’s still an optional. Instead of nil, we now assign a string to name. This 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)

We’ve discussed this before. A variable (or constant) can only be nil if its type is declared as an optional, with the question mark ?. The type of score is Int, which is not an optional, so it cannot be nil. In the previous example, name was declared as String?, which is an optional.

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.

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 4 different ways:

  1. With force unwrapping, using !
  2. With optional binding, using if let
  3. With implicitly unwrapped optionals, using !
  4. With optional chaining, using a?.b?.c

The 4th 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? = “[email protected]

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 after the optional constant or variable, like this:

print(email!)

Now, consider the following two scenarios:

  1. Instead of having a value, email is nil. What happens now?
  2. You don’t check if email is not nil. What happens?

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. Only use force unwrapping if you’re certain that the optional you’re unwrapping is not nil.

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”. I’m calling the constant optionalUsername here for the sake of the example.

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.

  • You can use guard let to unwrap optionals at the start of a function, and return the function if the optional is nil. Like this:

    guard let username = usernameField.text else {
    return
    }

    print(“Logged in user with username: \(username)”)

    One of the cool things about guard let is that you can use the created constant beyond the guard statement. It’s not declared inside the scope, like with if let, but in the same scope.

  • 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 tutorial.

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, but before the . period sign? This is optional chaining.

At this point, one of two things happens:

  1. The variable usernameField is not nil, and the call to property text succeeds
  2. 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” // Unsafe
textField?.text = “Arthur Dent” // Safer (but not bug-free)

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

  1. The first line, using force unwrapping, crashes!
  2. 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 tutorial, you can combine optional chaining in a number of elegant ways.

Let’s say you’re calling a function on an optional, with optional chaining. Like this: invoice?.sendReport(). What happens when invoice is nil? Does the report get sent or not? It’s not! The function isn’t called if invoice is nil, which can be a cause of hidden bugs. At this point it’s smart to debug why invoice is nil, and figure out how you can avoid that state.

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. When you access them, they’re implicitly and automatically unwrapped.

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 initialized, 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 typically 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.

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 2 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 four ways:

  1. With force unwrapping, using if optional != nil and optional!
  2. With optional binding, using if let constant = optional {
  3. With implicitly unwrapped optionals, using let optional:type!

  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 type 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.

Optionals, Enums and Generics

Under the hood, an optional is actually an enum. Like this:

public enum Optional :
{
case none
case some(Wrapped)

public init(_ some: Wrapped)

The Optional enum has two cases: nothing or none, and something or some. It’s either nil or has a value!

Because an optional is an enum, you can do some pretty magical things. Here, check this out:

let text = Optional.some(“42”)
print(type(of: text))
// Output: Optional

In the above code, we’re using the Optional type and its some(Wrapped) case to create an optional. The type of text is String?, which is represented as the generic type Optional.

In fact, the Optional enum uses the generic type placeholder Wrapped so that any type can be made optional!

In Swift, you don’t use the .none case, but instead we use nil. Here, check this out:

let name:String? = Optional.none
print(name)
// Output: nil

In the above code, the name optional is initialized with the Optional.none enum case. But when we print out the value of name, its output is nil! From this we can infer that nil and Optional.none are in fact the same value.

print(nil == Optional.none)
// Output: true

If an optional is an enum, we should be able to use the switch statement to deconstruct its cases. Like this:

let number:Int? = 42

switch number {
case .some(let unwrapped):
print(unwrapped)
case .none:
print(“nil”)
}

You can use the above sandbox. Change number to nil and then run the code. Do you see what happens? One of the cases is executed, based on the value of the optional. The some case has an associated value, of placeholder type Wrapped, that we’re printing out.

In practical iOS development, you wouldn’t use the Optional enum like this – but nevertheless, seeing where it comes from, is good fun!

Further Reading

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!


Aasif Khan

Head of SEO at Appy Pie

App Builder

Most Popular Posts