How do nullability annotations change what Swift sees, and what happens when they lie?
Predict first
What types does Swift report?
let p = Person()
print(type(of: p.name), type(of: p.nickname))
- String String
- String Optional<String>
- Optional<String> Optional<String>
Predict first
What happens? (Legacy.title is unannotated and is nil.)
let t: String = Legacy().title
print(t)
- Prints an empty string
- Crashes with “unexpectedly found nil”
Mental model. A nullability annotation is a label on a box saying “never empty”. If the packer ignores it, the person who opens the box finds nothing, and no one stopped it earlier.
Objective-C pointers can always be nil, so Swift needs to be told which ones can be. nonnull imports as T, nullable as T?, and null_resettable as T! for properties that accept nil but never return it. An unannotated pointer imports as an implicitly unwrapped T!: Swift lets you use it as a plain value and traps if it is actually nil. Wrap a header in NS_ASSUME_NONNULL_BEGIN / END to make everything non-null by default, then mark the exceptions nullable. C pointers use _Nonnull and _Nullable.
The annotations are a promise, not enforcement. If a nonnull method actually returns nil, nothing checks it in Objective-C, and Swift crashes or misbehaves when it uses the “non-optional” value. Audit headers, fix the implementation to honour them, and add annotations when you convert old code so that Swift callers get optionals where the data is truly optional.
Inside the nonnull region name imports as String; the property marked nullable becomes an optional.
An unannotated property imports as String!. Assigning it to a non-optional String force-unwraps it, and it is nil.
Common traps
- Leaving headers unannotated. Everything becomes
T!, and anilturns into a crash far from its cause. - Marking something
nonnullthat can be nil. The compiler trusts you, and Swift code force-unwraps it for free.
They might follow up with
- What does
initusually promise? Under the assume-nonnull region, a Swift initialiser that cannot fail. Usenullablefor failable ones. - How do you audit a big header? Add the region macros first, then fix compiler warnings about missing annotations one by one.