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 ☺️ 👇
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
}
}