Optional chaining
Optional chaining is a process in Swift that allows you to call properties, methods, and subscripts on optionals that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.
Basic Usage
Consider a class Person that has a property residence of type Residence?:
class Residence {
var numberOfRooms = 1
}
class Person {
var residence: Residence?
}
You could use optional chaining to call the numberOfRooms property on residence, like this:
let john = Person()
// Without optional chaining
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// Output: "Unable to retrieve the number of rooms."
Notice the ? after john.residence. This is the optional chaining. If residence exists, numberOfRooms is called on it. Otherwise, the whole expression returns nil.
Optional Chaining with Method Calls
You can use optional chaining on a method call that returns a value, and the return type will be an optional. Here's an example:
class Dog {
func makeSound() -> String {
return "Woof!"
}
}
class Person {
var pet: Dog?
}
let mary = Person()
if let sound = mary.pet?.makeSound() {
print("Mary's pet says: \(sound)")
} else {
print("Mary doesn't have a pet.")
}
// Output: "Mary doesn't have a pet."
Optional Chaining with Subscripts
You can use optional chaining with subscripts:
var testScores = ["Dave": [42, 82, 72], "Bev": [88, 77, 99]]
// Update Dave's first test score
testScores["Dave"]?[0] = 91
Here, the optional chaining checks if the key "Dave" exists in the testScores dictionary. If it does, then the value at index 0 is updated to 91.
Nested Optional Chaining
You can chain multiple optional chaining queries together. If any link in the chain is nil, the entire chain returns nil.
class Address {
var buildingName: String?
var street: String?
}
class Residence {
var address: Address?
}
class Person {
var residence: Residence?
}
let susan = Person()
if let street = susan.residence?.address?.street {
print("Susan's address is \(street).")
} else {
print("Unable to retrieve address.")
}
// Output: "Unable to retrieve address."
In the above code snippet, the optional chaining attempts to retrieve susan.residence?.address?.street. Both residence and address are optionals, and in this case, they are nil. Therefore, the entire optional chain returns nil.
Optional Chaining with Nil-Coalescing Operator
Optional chaining is often used in combination with the nil-coalescing operator ??:
let roomCount = john.residence?.numberOfRooms ?? 1
Here, roomCount will be 1 if john.residence or numberOfRooms is nil.
Optional chaining provides a concise, efficient way to traverse optional types in Swift, letting you write more robust and readable code.