Overview
Optional chaining is a Swift feature that lets you access properties, call methods, and read subscripts on a value that might be nil. You write a question mark before the next access, and Swift safely stops the chain if it finds nil.
If the optional contains a value, the access succeeds. If the optional is nil, the whole optional-chain expression returns nil instead of crashing.
Basic Syntax
Use ?. when the value on the left side is optional.
let result = optionalValue?.propertyThe result of optional chaining is always optional, even when the property you access is not optional. That is because the chain itself can fail.
Accessing a Property
Here is the core example from the original article, updated into the newer code block style:
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
john.residence = Residence()
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
}At first, john.residence is nil, so john.residence?.numberOfRooms also returns nil. After assigning a Residence, the optional chain succeeds and returns the room count.
Why the Result Is Optional
In the example above, numberOfRooms is an Int, not an Int?. But this expression still produces an Int?:
let roomCount = john.residence?.numberOfRoomsSwift wraps the result in an optional because john.residence might be nil. If the chain fails, Swift needs a way to represent "no room count was available."
Calling Methods
Optional chaining can also call methods on optional objects.
class Account {
var balance = 42.50
func formattedBalance() -> String {
"$\(balance)"
}
}
class Customer {
var account: Account?
}
let customer = Customer()
let balanceText = customer.account?.formattedBalance()
print(balanceText as Any)Because account is nil, the method is not called and balanceText becomes nil.
Chaining Multiple Levels
You can chain through several optional values in one expression.
class Profile {
var website: URL?
}
class User {
var profile: Profile?
}
let user = User()
let host = user.profile?.website?.host()
print(host as Any)If profile or website is nil, Swift stops and returns nil.
Using It with Subscripts
Optional chaining also works with subscripts, including dictionary lookups.
let settings: [String: [String: String]] = [
"profile": ["theme": "dark"]
]
let theme = settings["profile"]?["theme"]
print(theme as Any)The first dictionary lookup returns an optional dictionary. The ?["theme"] part safely reads the nested value only if the first lookup succeeds.
Combining with Nil Coalescing
Optional chaining pairs nicely with the nil coalescing operator when you want a fallback value.
let roomLabel = john.residence?.numberOfRooms ?? 0
print("Rooms: \(roomLabel)")If the chain returns nil, Swift uses the fallback value 0.
Common Mistakes
Forgetting that the result is optional
Even when the final property is not optional, optional chaining returns an optional result. You usually unwrap it with if let, guard let, or provide a fallback with ??.
Using optional chaining when the value is not optional
Only use ?. when the thing on the left side is optional. If the value is not optional, use normal dot syntax.
Hiding too much logic in one chain
Long chains can become hard to read. If an expression gets confusing, break it into smaller named values.
Quick Reference
| Syntax | What It Does |
|---|---|
person.residence?.numberOfRooms | Reads a property only if residence is not nil |
account?.formattedBalance() | Calls a method only if account exists |
settings["profile"]?["theme"] | Reads a nested subscript safely |
chain ?? fallback | Provides a fallback when the chain returns nil |
Summary
- Optional chaining uses
?.to safely access optional values. - If any optional in the chain is
nil, the whole expression returnsnil. - Optional chaining works with properties, methods, and subscripts.
- The result of optional chaining is optional.
- Use
if let,guard let, or??to handle the optional result.
Optional chaining helps you write Swift code that is safer and easier to read. It lets you ask for a value only when the path to that value exists, without turning every access into a long set of nested checks.