Skip to content

Latest commit

 

History

History
81 lines (58 loc) · 3.53 KB

15.0 - Optional Chaining.md

File metadata and controls

81 lines (58 loc) · 3.53 KB

Optional Chaining is a syntax for chaining together calls to optional methods, properties and subscripts. If any item in the chain returns null, the whole chain fails gracefully and returns null. It can be an effective tool for writing beautiful code and reducing the boilerplate code associated with optionals.

Optional Chaining as an Alternative to Forced Unwrapping

Optional Chaining can be used in place of forced unwrapping (indicated using the ! syntax). The main difference in doing so is that with Forced Unwrapping, if a nil is returned, a runtime error will trigger. With Optional Chaining, the call will fail gracefully.

Note that to facilitate this, an optional chain will always return an Optional type.

For example:

class Person {
    var residence: Residence?
}
 
class Residence {
    var numberOfRooms = 1
}

let john = Person() //residence == nil

let failedRoomCount = john.residence!.numberOfRooms
// this triggers a runtime error

let successRoomCount = john.residence?.numberOfRooms
// successRoomCount does not trigger an error.
//Instead successRoomCall == nil

Accessing Properties Through Optional Chaining

We can also set properties using optional chaining, though you need to be careful you do not make your code hard to read. So for instance, the following code is valid, but the numberOfRooms will not be set because residence is not set:

john.residence?.numberOfRooms = 5

Calling Methods Through Optional Chaining

You can also call methods through optional chaining. For instance, if we add the following method to the Residence class:

func printNumberOfRooms() {
    print("The number of rooms is \(numberOfRooms)")
}

we can actually test to see if its been called using code like the following:

if john.residence?.printNumberOfRooms() != nil {
    print("It was possible to print the number of rooms.")
} else {
    print("It was not possible to print the number of rooms.")
}
// Prints "It was not possible to print the number of rooms."

Note that, interestingly, printNumberOfRooms() has a return type of Void, but when part of an Optional chain, its return type becomes Void?.

This method of checking to see if an operation has succeeded also works with property assignment. For instance, a better way to write the code snippet in the "Accessing Properties Through Optional Chaining Section" would be:

if (john.residence?.numberOfRooms = 5) != nil {
    print("It was possible to set the number of rooms to five.")
} else {
    print("It was not possible to set the number of rooms.")
}
// Prints "It was not possible to set the address."

Accessing Subscripts Through Optional Chaining

It is also possible to access subscripts using optional chaining. If we were to add subscripts to the residence class for instance, we could integrate it into an optional chain using syntax like:

john.residence?[0] = Room(name: "Bathroom")

Note that the ? appears before the []. This is because the optional item is the residence, not the indexed item. The optional chaining question mark always follows immediately after the part of the expression that is optional.

Previous Section | Back To Contents | Next Note