Optionals
An optional is some(T) or none — Swift’s answer to null. The type system forces you to acknowledge nil before using the value. Force-unwrapping (!) is a crash waiting to happen.
Unwrap safely, chain, nil-coalesce
EXAMPLE
// 1) Declaring optionals
var name: String? = nil // explicit
var count: Int = 0 // non-optional
// var x: String = nil // ERROR — non-optional can't be nil
// 2) if let — unwrap and bind
if let n = name {
print("Hello, \\(n)")
} else {
print("No name")
}
// 3) guard let — early exit (common in functions)
func greet(_ name: String?) {
guard let name else {
print("No one to greet")
return
}
print("Hello, \\(name)")
}
// 4) Optional chaining — short-circuit nil through a chain
struct Address { var city: String? }
struct User { var address: Address? }
let user: User? = User(address: Address(city: "Sydney"))
let city = user?.address?.city // String? — Sydney
let len = user?.address?.city?.count // Int? — 6
// 5) Nil-coalescing — provide a default
let display = user?.address?.city ?? "Unknown"
let score = scoreFromAPI ?? 0
// 6) Optional binding in conditions
if let user, let city = user.address?.city {
print("\\(user.id) in \\(city)")
}
// 7) Optional pattern matching
let x: Int? = 7
switch x {
case .some(let v): print("got \\(v)")
case .none: print("empty")
}
// Modern: switch x { case let v?: ... ; case nil: ... }
// 8) map / flatMap — transform without unwrapping
let len2 = name.map { $0.count } // Int?
let first = words.first.flatMap { Int($0) } // Int?, nil if word isn't a number
// 9) Force unwrap — ONLY when you're certain
let url = URL(string: "https://example.com")! // crash if invalid
// Prefer:
guard let url = URL(string: someString) else { return }
// 10) Implicitly unwrapped — for late init that's guaranteed before use
// (e.g. IBOutlets, dependency injected later)
@IBOutlet weak var label: UILabel!
// 11) Conditional cast — as? returns optional
if let user = obj as? User {
print(user.name)
}
// 12) Multiple values
let first = name ?? email ?? "Anonymous"
// 13) Common bug — comparing to .some explicitly
if name != nil { ... } // works but Swift-y is `if let name`
// 14) Throwing alternative — when nil means "explain why"
enum ParseError: Error { case empty, badFormat }
func parseAge(_ s: String) throws -> Int {
guard !s.isEmpty else { throw ParseError.empty }
guard let n = Int(s) else { throw ParseError.badFormat }
return n
}
Why it matters
Reach for guard let over if let in functions — it keeps the happy path un-indented and forces an early return for the nil case. Force-unwrap (!) only when failure should crash the app.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
var maybe: String? = nil
maybe = "Ada"
if let n = maybe {
print("got \(n)")
}
let length = maybe?.count ?? 0
Try it Yourself »
Exercise
Default value when nil.
let len = name
0
Two characters.
Discussion
Loading…