๐ŸŽ“ A1Learner
๐Ÿ”
0 of 36 lessons completed

Swift Optional Chaining in Depth

Optional chaining in depth is reaching through several optional values in one chain. Each link stops the chain quietly when its value is nil.

Two optional links in one chain

The address is optional and the city inside it is optional too. Ana reaches a city and Bo settles with the fallback.

struct Address {
    var city: String?
}
struct Person {
    var name: String
    var address: Address?
}
let ana = Person(name: "Ana", address: Address(city: "York"))
let bo = Person(name: "Bo", address: nil)
print(ana.address?.city ?? "no city")
print(bo.address?.city ?? "no city")

A method call through a stopped chain

The call to uppercased runs only when both links before it hold values. A nil address and a nil city each settle with the same fallback.

struct Address {
    var city: String?
}
struct Person {
    var name: String
    var address: Address?
}
let ana = Person(name: "Ana", address: Address(city: "York"))
let bo = Person(name: "Bo", address: nil)
let cy = Person(name: "Cy", address: Address(city: nil))
print(ana.address?.city?.uppercased() ?? "NO CITY")
print(bo.address?.city?.uppercased() ?? "NO CITY")
print(cy.address?.city?.uppercased() ?? "NO CITY")

Assigning through a chain

The first assignment reaches a held address and changes its city. The second assignment stops at the nil address and changes nothing.

struct Address {
    var city: String?
}
struct Person {
    var name: String
    var address: Address?
}
var ana = Person(name: "Ana", address: Address(city: "York"))
var bo = Person(name: "Bo", address: nil)
ana.address?.city = "Leeds"
bo.address?.city = "Leeds"
print(ana.address?.city ?? "no city")
print(bo.address?.city ?? "no city")

Three optional links in one chain

This chain passes through a team and a company before it reaches a name. Bo holds no team, so the whole chain settles with the fallback.

struct Company {
    var name: String?
}
struct Team {
    var company: Company?
}
struct Worker {
    var team: Team?
}
let ana = Worker(team: Team(company: Company(name: "Acme")))
let bo = Worker(team: nil)
print(ana.team?.company?.name ?? "no company")
print(bo.team?.company?.name ?? "no company")

Example

struct Address {
    var city: String?
}
struct Person {
    var name: String
    var address: Address?
}
var sam = Person(name: "Sam", address: Address(city: "York"))
var dee = Person(name: "Dee", address: nil)
sam.address?.city = "Hull"
dee.address?.city = "Hull"
print(sam.address?.city?.lowercased() ?? "no city")
print(dee.address?.city?.lowercased() ?? "no city")
print(sam.address?.city ?? "no city")

Key points

  • A chain can pass through more than one optional value in a single line.
  • The result of a chain stays optional when any link in the chain is optional.
  • The ?? operator settles a finished chain with a plain fallback value.
  • Calling a method through a chain gives nil when an earlier link holds nil.
  • Assigning through a chain changes a value only when every link holds a value.
  • Reading a property two links deep follows the same stop rule at each link.

In this example, Sam holds an address with the city York and Dee holds no address. The assignment through the chain changes the city of Sam to Hull. The same assignment for Dee stops at the nil address and changes nothing. The first print chains into lowercased and shows hull. The second print settles with no city. The last print reads the stored city of Sam and shows Hull.

Note

A stopped chain is a normal result and the program keeps running.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A person holds a nil address. What does printing person.address?.city ?? "no city" give?