Skip to content
AgileLogics
5 min read

Optional Chaining and Optional Patterns

Prerequisites: Unwrapping optionals safely, Structs

Real data is often nested, with optionals at several levels. A few tools keep that code short.

Optional chaining

?. calls a property or method only if the value before it isn't nil. If any link in the chain is nil, the whole expression is nil:

struct Address { let city: String }
struct Company { let address: Address? }
struct Person { let name: String; let employer: Company? }

let ada = Person(name: "Ada", employer: Company(address: Address(city: "London")))
let sam = Person(name: "Sam", employer: nil)

print(ada.employer?.address?.city ?? "unknown")
print(sam.employer?.address?.city ?? "unknown")
print(sam.employer?.address?.city.count ?? 0)
London
unknown
0

The result of a chain is always optional, so it's usually combined with ?? or if let.

Unwrapping several at once

if let and guard let can unwrap several values, and mix in conditions, separated by commas. Everything must succeed:

func shippingLabel(name: String?, city: String?, zip: String?) -> String {
    guard let name, let city, let zip, zip.count == 5 else {
        return "Incomplete address"
    }
    return "\(name), \(city) \(zip)"
}

print(shippingLabel(name: "Ada", city: "Boston", zip: "02101"))
print(shippingLabel(name: "Ada", city: nil, zip: "02101"))
Ada, Boston 02101
Incomplete address

Transforming an optional with map

map on an optional transforms the value if there is one, and keeps nil otherwise:

let input: String? = "42"
let doubled = input.flatMap { Int($0) }.map { $0 * 2 }
print(doubled ?? 0)
84

flatMap is used here because Int($0) itself returns an optional — flatMap avoids ending up with an optional inside an optional.

Common mistakes

  • Force-unwrapping in the middle of a chain (a!.b!.c). One nil anywhere crashes the program. Use ?. and handle nil once at the end.