How it works
The explanation, with examples you can run.
Getting the value out
struct Address { var city: String? }struct User { var name: String; var address: Address? } func greeting(for user: User?) -> String { guard let user else { return "Hello, stranger" } // Swift 5.7 shorthand for guard let user = user let city = user.address?.city ?? "somewhere" // chain, then default return "Hello \(user.name) from \(city)"} print(greeting(for: nil)) // Hello, strangerprint(greeting(for: User(name: "Ada", address: Address(city: "London")))) // Hello Ada from Londonprint(greeting(for: User(name: "Bo", address: nil))) // Hello Bo from somewhere if let n = Int("42") { print(n + 1) } // 43if let x/guard let xbind a non-optional name. Since Swift 5.7 you can leave out= xwhen the names match.guardmust leave the scope in itselse, and the bound name stays available afterwards, which keeps the main path flat.- Optional chaining
a?.b?.c()evaluates tonilas soon as one link isnil. The result is always a single optional, however long the chain. - Nil-coalescing
a ?? bgives the wrapped value orb. The right side is only evaluated when needed. mapandflatMaptransform the wrapped value:Int(text).map { $0 * 2 }.switchworks too, withcase .some(let v)or thecase let v?pattern, because it is just an enum.
Force-unwrapping
value! returns the wrapped value or traps: the program stops with "Unexpectedly found nil while unwrapping an Optional value". Treat each ! as an assertion that nil is impossible here, and prefer a guard with a useful failure, or precondition, when it really is a programmer error.
Implicitly unwrapped optionals (var label: UILabel!) are optionals that unwrap themselves on use. They exist for values that can't be set in init but are always set before use, such as Interface Builder outlets. Anywhere else, a plain optional or a non-optional with a proper initialiser is safer.
Optionals and Objective-C
APIs from Objective-C come in with nullability from their annotations (nullable, nonnull, or a whole header in NS_ASSUME_NONNULL_BEGIN). Unannotated pointers are imported as implicitly unwrapped optionals, Swift's way of saying "unknown". The idea is close to Kotlin's platform types: the uncertainty sits at the border, so handle it there.
Design tips
Don't make something optional because it is convenient; make it optional because "missing" is a real state. An Optional<Bool> with three states is usually an enum waiting to be written. And Optional of a collection is rarely needed: an empty array usually says the same thing.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.