Optional chaining lets you safely access properties or call methods on values that might be nil (empty). It helps avoid crashes by stopping if something is nil.
Optional chaining with ?. in Swift
class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() let roomCount = john.residence?.numberOfRooms
The ? after residence means: if residence is nil, stop and return nil instead of crashing.
Optional chaining returns an optional value, so roomCount is an Int? (optional Int).
residence is nil, so optional chaining stops and roomCount is nil.class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() // residence is nil, so this returns nil let roomCount = john.residence?.numberOfRooms print(roomCount) // prints nil
residence exists, so optional chaining accesses numberOfRooms and returns it wrapped in Optional.class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } let john = Person() john.residence = Residence() // residence is not nil, so this returns 1 let roomCount = john.residence?.numberOfRooms print(roomCount) // prints Optional(1)
class Person { var residence: Residence? } class Residence { var rooms: [String] = [] func printNumberOfRooms() { print("Number of rooms: \(rooms.count)") } } let john = Person() john.residence = Residence() // Call method safely with optional chaining john.residence?.printNumberOfRooms() // prints "Number of rooms: 0"
class Person { var residence: Residence? } class Residence { var rooms: [String] = [] func addRoom(name: String) { rooms.append(name) } } let john = Person() // This does nothing because residence is nil john.residence?.addRoom(name: "Living Room") // residence is still nil print(john.residence?.rooms.count) // prints nil
This program shows optional chaining stopping safely when residence is nil, then working after residence is set.
class Person { var residence: Residence? } class Residence { var rooms: [String] = [] func addRoom(name: String) { rooms.append(name) } func printNumberOfRooms() { print("Number of rooms: \(rooms.count)") } } // Create a person without a residence let john = Person() // Try to print number of rooms safely john.residence?.printNumberOfRooms() // Nothing prints because residence is nil // Add a residence john.residence = Residence() // Add rooms safely john.residence?.addRoom(name: "Living Room") john.residence?.addRoom(name: "Kitchen") // Print number of rooms again john.residence?.printNumberOfRooms()
Time complexity: Optional chaining itself is O(1) because it just checks for nil and accesses properties or calls methods.
Space complexity: No extra space is used beyond the objects themselves.
Common mistake: Forgetting that optional chaining returns an optional, so you might need to unwrap the result.
Use optional chaining when you want to safely access or call on optionals without many if-let checks. Use if-let if you want to unwrap and use the value immediately.
Optional chaining safely accesses properties or methods on optionals.
It stops and returns nil if any part is nil, avoiding crashes.
It returns an optional value, so you may need to unwrap it later.