In programming, there are times that you need to represent the concept of no value. Take a form field for example where you ask users to enter their age. Assuming that response
represents the entered text, you can use the toInt()
method of the String class to store the user’s age in a constant:
1
|
|
When response has an integer representation, say “32” for example, toInt()
returns a value, but what if the user entered something like “None of your business”? In cases like this, we need some way to represent no value.
Objective-C uses nil
and NSNotFound
to represent the concept of no value; Swift uses optionals.
An optional is Swift’s way of saying: there might be Some value or there might be None.
To mark a value as optional, we add a question mark (?) after the type of the value.
Here’s an example:
1
|
|
Here, age
might contain some integer or might contain no value.
As an aside, you can specify a variable has no value by assigning it nil
. Optional variables or constants that are defined without default values are automatically set to nil
. In the above example, the value of age
is nil
.
Using Optionals
Since an optional might return nil
, we want to check if it contains any value before using it. This can be done by comparing it against nil
.
1 2 3 4 5 |
|
We now know that firstName does in fact contain some value, but if you try using it in println(), the result might surprise you.
1 2 3 |
|
And this brings us to something that might be confusing at first, so read the next paragraph carefully.
A string optional declaration doesn’t mean your variable contains either no value or a string. It means that your variable either contains no value or it contains an optional of type String.
A look at the Swift header file makes this more clear.
1 2 3 4 5 |
|
As you can see, an optional is its own type, an enum in fact, that can return either None
or Some(T)
, where T
is an associated value of the correct type.
Therefore, before using an optional, you need to first access its underlying value.
Before moving any further, let’s take a look inside our firstName
variable and see what’s going on at a lower level using fr v -R
in LLDB:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Compare this with the case where firstName
has no value (is nil
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
This is quite complicated, but still easy enough to see how the compiler handles the Some and None cases and keeps track of the underlying value.
Unwrapping Optionals
The are two ways to access the underlying value of an optional: forced unwrapping and optional binding.
Forced unwrapping
If you are certain that an optional contains a value, you can access the underlying value by force unwrapping the optional. This is done by adding an exclamation mark to the end of the optional’s name.
Going back to our previous example, we can now access the String value in firstName
:
1 2 |
|
Warning: if you try to force-unwrap an optional that contains no value, you’ll get a runtime error and your app crashes.
By using forced unwrapping, you are promising the compiler that the optional will have a value at runtime, and it can be unwrapped. You better make good on that promise if you don’t want a crash on your hands!
Optional binding
Optional binding is a rather elegant way of unwrapping an optional with the help of a temporary constant or variable.
The syntax is like this:
1 2 3 |
|
Here, the compiler checks someOptional
to see if it contains a value or not. If there’s a value, it will be assigned to the temporary constant actualValue
, which can be used inside the if
block.
You can also use an else
statement to handle the case where someOptional
contains no value.
Let’s use optional binding to unwrap the value of our firstName
variable:
1 2 3 4 5 6 7 |
|
Implicitly Unwrapped Optionals
Often the only time an optional has no value when it’s first defined. In other words, you know that after the value is initially set, the optional always has a value.
Implicitly unwrapping an optional allows you to use its underlying value, without having to nil-check or unwrap it.
An implicitly unwrapped optional is declared by placing an exclamation mark after the type (instead of a question mark).
1
|
|
Implicitly unwrapping an optional is the equivalent of asking the optional to automatically unwrap itself each time it is used. For example, you can use buttonWidth
from the above example, like a normal variable without having to unwrap its value first.
Of course, if your assumption is false, and the optional is nil
at some point, you’ll have a runtime error.
Let take a look at an example:
1 2 3 4 5 6 7 8 |
|
Here, you know that by the time that awakeFromNib()
is called, all the outlets are guaranteed to have been configured. So, it’s perfectly safe to use button
in awakeFromNib()
or viewDidLoad()
without worrying about it returning nil
. And this is why we declare it as an implicitly unwrapped optional.
While we are on this topic, Apple recommends using implicitly unwrapped optionals for outlets:
When you declare an outlet in Swift, you should make the type of the outlet an implicitly unwrapped optional. This way, you can let the storyboard connect the outlets at runtime, after initialization. When your class is initialized from a storyboard or xib file, you can assume that the outlet has been connected.
Excerpt from Using Swift with Cocoa and Objective-C
Nil Coalescing Operator
If you are a fan of ternary conditional operator like yours truly, you gonna like this one, despite the somewhat funky name!
Nil coalescing operator allows you to unwrap an optional if it has a value, or use a default value if the optional is nil
. The syntax is:
Note: Unfortunately I cannot use ⁇ in code blocks, so there is an extra space between the questions marks in the following blocks. There is no space between question marks in the nil coalescing operator.
1
|
|
And similar to ternary operator, nil coalescing operator is usually used in assignments:
1
|
|
Let’s look at an example:
1 2 3 4 |
|
Here, if our user has already selected a colour theme and userColorTheme
has a value, it will be unwrapped and assigned to colorTheme
. If userColorTheme
is nil
on the other hand, the defaultColorTheme
will be assigned to colorTheme
.
Optional Chaining
Optional chaining is a mechanism for querying optionals. It is specially useful when dealing with nested optionals in classes or structs. Consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
One way to check the guarantor’s credit score for a rental unit is using implicitly unwrapped optionals:
1
|
|
The problem with this approach is if a rental unit has no guarantor, or if the guarantor doesn’t have a credit score, we’ll end up with a runtime error!
Nested if let
statements don’t make a very elegant solution either:
1 2 3 4 |
|
Optional chaining is the answer in such cases. The syntax is similar to that of implicitly unwrapped optionals. All you need to do is to replace the exclamation marks (!) with question marks (?):
1 2 |
|
Here, the links in the chain are checked sequentially. For each link, if there’s a value, it will be unwrapped and the process continues to the next link. If it there’s no value, nil
is returned and the entire chain fails gracefully.
Important: The result of an optional chaining call is always an optional value, even when the query returns a non-optional value.
Let’s take a look at an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Here, regardless of the fact that university is a non-optional String, since we accessed it with optional chaining, a String? is returned. Therefore, we need to first unwrap the optional String before using its value:
1 2 3 4 5 6 |
|
References: