if let vs guard let vs ?? vs force unwrap — when is each one OK?
Predict first
Does this compile?
func show(_ s: String?) {
if let s { print(s) }
print(s.count)
}
- Yes
- No
Mental model. guard let is a bouncer at the door: no ticket, no entry, and the rest of the room can relax. if let is a side room you only enter when you have a ticket.
if let x { ... } binds x only inside the true branch — use it when the nil case is a normal branch among several.
guard let x else { return } binds x for the rest of the enclosing scope and must exit on failure. Use it at the top of a function to flatten the happy path.
?? supplies a default and always produces a non-optional. Use it when a sensible fallback exists.
! is only defensible when you can prove the invariant within one screen: an @IBOutlet after viewDidLoad, or a value you just constructed non-nil. Never force-unwrap network or JSON data — that is exactly where the unexpected lives.
if let unwraps only inside its braces. Outside, s is still String?. guard let is the one that keeps the unwrapped name for the rest of the scope.
| if let | guard let | ?? | ! | |
|---|---|---|---|---|
| Unwrapped name lives | inside the braces | rest of the scope | no name, just a value | that expression |
| When nil | runs else | must exit | uses the default | crashes |
| Best for | optional work | preconditions | sensible defaults | proven invariants |
Common traps
- Writing
if let x = xon modern Swift. Since Swift 5.7 the shorthand isif let x { }. The long form still works but reads as dated. - Using
??to hide a real failure. A silent default can turn “the server did not send a token” into “we sent an empty token” — much harder to debug.
They might follow up with
- What is
guardrequired to do? Exit the scope:return,throw,break,continue, or call aNeverfunction. - Can you
guard letmultiple values? Yes, comma-separated:guard let a, let b, a < b else { return }.
Related questions
- 1.2.4 What does guard buy you beyond if?
- 1.2.6 How does optional chaining (a?.b?.c) actually work?
- 1.2.2 Why can switch on an Optional use .none / .some and also nil?
← Why can switch on an Optional use .none / .some and also nil? What does guard buy you beyond if? →