Swift Optional values
What is an optional?
In Swift an optional is a variable that either contains a value, or is missing, that is to say nil
(in most languages the term null
is used).
As we know this value might be missing at runtime, a safety is put at compile time to ensure we check it has a content before actually using it. The operation that gives us access to the actual value of the variable is called unwrap.
How to declare an optional?
We specify a variable being an optional simply by appending the ? character after its type during the declaration.
- Non optional:
var nonOptional: Int
- Optional:
var optional: Int?
How to unwrap an optional?
There is three way doing so:
- Using a condition or a guard
- Using the safe unwrap operator ?
- Using the force unwrap operator !
- Using the unwrap with default value operator ??
Unwrapping through a condition or a guard
Inside a condition
if let nonOptional = optional {
// nonOptional value can be used inside the condition
}
// nonOptional value can't be used after the condition
After a guard:
guard let nonOptional = optional else {
return // or other exit
}
// nonOptional value can be used after the guard
Unwrapping through the safe unwrap operator ?
This is used to call method on an object only if it is not nil.
myOptionalObject?.myMethod()
// myMethod will be called only if myOptionalObject has an actual value
Unwrapping through the force unwrap operator !
This could be used if we are at least 100% sure the variable does have an actual value. If it does not it will throw a "Unespectdly found nil white unwrapping an Optional value".
While calling a method:
myOptionalObject!.myMethod()
// myMethod will be called without checking if myOptionalObject is nil or not.
While working with a value:
let myComputedValue = compute(myOptionalValue!)
At declaration time, usualy for outlets (links to User interface elements)
@IBOutlet weak var myLabel: UILabel!
// myLabel must be an optional because it itsn't accessible at init time, only after the view has been loaded
override func viewDidLoad() {
super.viewDidLoad()
myLabel.text = "No need to unwrap"
// we use myLabel like if was a non optional value
}
Without the force unwrap at declaration time we would have written something like:
@IBOutlet weak var myLabel: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
myLabel?.text = "No need to unwrap"
}
Unwrapping with default value
This is used to retrieve the actual content of an optional value, or use a default value if it is nil.
Lets look at this example:
var myOptionalValue: Int?
// somecode where myOptionalValue might got a value or remain nil
let myNonOptionalValue = myOptionalValue ?? 2
It is a shorter equivalent to:
var myOptionalValue: Int?
// somecode where myOptionalValue might got a value or remain nil
let myNonOptionalValue: Int
if let unwrapped = myOptionalValue
myNonOptionalValue = unwrapped
else
myNonOptionalValue = 2