3 mistakes to avoid with Optionals


You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿


I want to tell you about 3 mistakes you want to avoid when working with Optionals in Swift!

#01 – Not understanding the difference between ? and !

Take a look at this code: I create an optionalString, that will hold either the string “Hello, world!” or nil.

And then I call the method .reversed() on that optionalString:

But notice how I call that method using two very different syntaxes: in the first case I use a “?” but in the second case I use an “!.

When you’re new to Swift, this difference might seem like a detail, but it’s actually really important!

The first syntax, that’s called ”optional chaining”, will return an Optional.

Meaning that when optionalString actually holds a String, that optional will contain the reversed string, and when optionalString is nil that optional will also be nil.

This optional chaining syntax is very useful because it allows us to interact with optionals in a very safe way.

Its only downside is that we need to deal with an Optional return value.

On the other hand, the second syntax, that’s called “force unwrapping”, will not return an Optional.

But this apparent simplicity comes at a price: should optionalString be nil, then this second syntax will lead to a crash.

So most of the time, you probably want to use the first syntax called optional chaining, because it offers a much safer way to interact with an optional 😌

#02 – Not using Optional Binding

Another big pitfall of optionals is to not unwrap them in a way that is error proof.

Take a look at this code: first I test that the optional isn’t nil, and then, inside the if statement, I force unwrap the optional.

At first glance this might seem like a reasonable approach.

But the issue lies in the fact that the force unwrap is happening independently of the condition.

So if we later change the condition to something completely different, the force unwrap will still successfully build, however there is now a chance that this force unwrap will lead to a crash…

Fortunately, Swift comes with a built-in feature that is specifically made to solve this issue.

By using optional binding, we are able to write a condition that will test whether the optional is nil, and that will also create a new non-optional value that we can safely access inside the if statement.

Even better, since the Swift 5.7, that optional binding syntax has become even shorter!

#03 – Using an Optional when it is not needed

Finally, the last mistake you want to avoid is to use an Optional when it is actually not needed.

Here I’ve defined a struct that represents a Person and I chose to represent the name of that Person as an Optional:

However notice that in the initializer of the struct, the name is not optional.

This means that it’s actually impossible to create a Person whose name is nil.

So it actually makes no sense to store the name as an Optional, because it doesn’t solve any problem and only brings additional complexity:

Of course, here my example might feel a bit far fetched.

But I assure you that when you work in a real app, it’s actually easier than you think to end up in a situation where a value has been declared as optional for absolutely no good reason.

So as a rule of thumb, I would suggest you should start by making a value non-optional by default, and only turn it into an Optional when it’s actually required 👌

Conclusion

That’s it, these were the 3 mistakes you definitely want to avoid when using Optionals in Swift!

I hope you’ve enjoyed this article and that it will help you improve the quality of your code!


You’ve enjoyed this article and you want to support my content creation?

You can leave me a tip ☺️ 👇

Buy Me A Coffee

Here’s the code it you want to experiment with it!

import Foundation

// #01 - Not understanding the difference between `?` and `!`

let optionalString: String? = Bool.random() ? "Hello, world!" : nil

// Optional Chaining
optionalString?.reversed() // will return `nil` if `optionalString` is `nil`

// Force Unwrapping
optionalString!.reversed() // will crash if `optionalString` is `nil`

// #02 – Not using Optional Binding

if let optionalString {
    // `optionalString` is now of
    // type `String` inside this scope
    print(optionalString.reversed())
}

// #03 - Using an Optional when it is not needed

struct Person {
    let id: UUID
    let name: String

    init(name: String) {
        self.id = UUID()
        self.name = name
    }
}
Previous
Previous

Discover LazySequence

Next
Next

Here are 5 (new) tips you can start using today 🚀