Optionals in Swift
Every variable can be declared as a so-called optional in Swift. As an optional, the variable is allowed to become nil what is equivalent to the absence of a value.
Hint: This post has been updated to Swift 3
Optionals
If you have a variable that is not an optional, it must have a value:
var i:Int = 5
In this example, the integer i has a value of 5. If we now try to assign nil to i, there will be a compiler error:
i = nil //Compiler error!
Normally this is a desired behavior because accessing nil at runtime would lead to an error. But there are circumstances where a variable has to have the possibility to become nil . For example, this can be the case, if you are interacting with Objective-C API. Or, if it does make logical sense for the value to become nil.
For this scenario there are optionals. A variable is an optional, if you mark the corresponding type with a question mark:
var j: Int? = 5
You can do this with every type in Swift! Contrary to a normal value, j is now allowed to be nil:
j = nil
But on the other hand, it is not allowed to access an optional the same way you access non-optional values!
i = 5 + j //Compiler error!
Unwrapping Optionals
To access an optional, you need to explicitly unwrap it. This means “Hey complier, I know that this value could theoretically be nil but I know what I am doing…”. You unwrap an optional with a exclamation mark:
i = 5 + j!
But you should really be very sure what you are doing… If you unwrap an optional and it is nil, then there will still be an error at runtime!
So it is very advisable to check, whether the optional is not nil . The most obvious – but not best – way to do this, is by using an if condition:
if j != nil { i = 5 + j! }
If we know that j is not nil, there is no danger to unwrap it.
Optional Binding
A better way to check whether an optional is nil or not is by using the so-called optional binding. It is a special case of the if condition. Only if the optional is not nil the condition is fulfilled and you can use a new non-optional variable:
if let j = j { i = 5 + j }
This has the big advantage that you do not need to use the unwrapping operator.
Within the if block, j is a non-optional!
guard
Since Swift 2 there is another way to check whether an optional is nil or not. For this, there is the keyword guard. It is used if you want to assure that a certain condition holds true. Otherwise you have to take care of leaving the current scope. You can use guard wherever you can use one of the keywords return, break, continue or throw.
Let us define a method that takes an optional as an argument. We could use optional binding to check whether we can use the optional or not:
func guardExample(i:Int?) { if let i = i { print("i is not equal nil...") // lots of code... } else { print("i is equal nil..") } }
However, now the whole function lives in the first part of the if condition. Instead you can use guard:
func guardExample(i:Int?) { guard let i = i else { print("i is equal nil...") return } print("i has the value \(i)") }
In this case, we use guard in combination with optional binding. If i is equal nil, we take care of the situation and leave the method by using return. Otherwise, we can hereafter use i as a non-optional.
Optional Chaining
Optional chaining is another way of accessing an optional. It can be used if you want to call a property or a function of an optional.
Imagine you have two classes Vehicle and Garage:
class Vehicle { var numberOfWheels: Double init(numberOfWheels:Double) { self.numberOfWheels = numberOfWheels } } class Garage { var vehicle: Vehicle? }
Now we create a vehicle and a garage:
let aVehicle = Vehicle(numberOfWheels: 4) let aGarage = Garage()
If we now want to access the optional property numberOfWheels of the garage’s vehicle, we could do it the following way with optional binding:
if let vehicle = aGarage.vehicle { var numberOfWheelsVersion1 = vehicle.numberOfWheels print("\(numberOfWheelsVersion1)") }
However, it will get a little bit complicated if the vehicle has another optional and we want to access an optional of an optional then. So there is the possibility to access the garage’s vehicle by the so-called optional chaining.
For accessing the optional we use a question mark. Take a look at the following example:
var numberOfWheelsVersion2 = aGarage.vehicle?.numberOfWheels print("\(numberOfWheelsVersion2)") //output: nil aGarage.vehicle = aVehicle var numberOfWheelsVersion3 = aGarage.vehicle?.numberOfWheels print("\(numberOfWheelsVersion3)") //output: 4
The result is that the accessed variable becomes an optional. In the first case where the garage doesn’t have a vehicle, numberOfWheelsVersion2 is nil. But in the second case we first assign a vehicle to the garage and then numberOfWheelsVersion3 is 4. However, numberOfWheelsVersion3 is still an optional of double!
It is also possible to call functions with optional chaining. Let’s add a function to the class Vehicle:
class Vehicle { var numberOfWheels: Double init(numberOfWheels:Double) { self.numberOfWheels = numberOfWheels } func start() { print("starting the vehicle...") } }
Now we can call the function like this:
aGarage.vehicle?.start()
If the garage’s vehicle is not equal nil, then start is called. On the other hand if the vehicle is equal nil , then start will not be called. It is also possible to check whether it is called or not:
if aGarage.vehicle?.start() != nil { print("start is called...") } else { print("start is not called...") }
Implicit Unwrapped Optionals
Furthermore, there are so called implicit unwrapped optionals. These are a special kind of optionals that are in fact real optionals but can be accessed as non-optionals. They are defined with an exclamation mark:
var m: Int! = 5
Like optionals you can assign nil to them:
m = nil
Then, they can be accessed without unwrapping – like a non-optional:
i = 5 + m
However, if the implicit unwrapped optional is nil, accessing it will result in a runtime error! So you should use implicit unwrapped optionals only if you are very sure that the value will never be nil! But was: it is always possible that someone assigns nil to the value… So, better use it very rarely!
A general rule for using optionals
Here are two important points for using optionals:
- Do not force unwrap optionals!
- Do not use implicit unwrapped optionals!
Of course there are situations where it does make sense to do one of these two things. But they are very rare and should only be done very carefully!
[thrive_text_block color=”blue” headline=”Conclusion”]Optionals are a very important language feature in Swift. For beginners all the exclamation and question marks can be a little confusing. But if you get used to it, you will be able to write very safe and powerful code.[/thrive_text_block]
References
The Swift Programming Series (iBook Store)
Image: @ jijomathaidesigners / Shutterstock.com