Sometimes a value simply isn't there. A user might not have a middle name, a search might find nothing, the text someone typed might not be a valid number. Swift represents "no value" with nil.
In many languages any variable can secretly be nil, and using one by mistake crashes the program. Swift solves this at the type level. A normal String always contains a string. If a value might be missing, its type must say so with a question mark: String?, an optional string. The compiler then insists that you check for nil before using it, so the check can't be forgotten.
Optionals are everywhere in Swift, so handling them fluently is an essential skill. In this lesson you'll create optionals, unwrap them safely with if let and guard let, provide defaults with ??, call methods through them with optional chaining, and learn why force unwrapping with ! is best avoided.
Optional types and nil
var nickname: String? = "Addy"
nickname = nil // allowed: it's optional
var name: String = "Ada"
name = nil // error: 'nil' cannot be assigned to type 'String'- Any type can be optional:
Int?,Double?,[String]?. - An optional either contains a value or is
nil. - Printing an optional shows
Optional("Addy")ornil, a sign you should usually unwrap it first. - Many functions return optionals because they can fail:
Int("42")returnsInt?, andarray.firstreturns nil for an empty array.
if let and guard let
if let unwraps an optional and runs a block only when there's a value:
if let nick = nickname {
print("Hi, \(nick)") // nick is a plain String here
} else {
print("No nickname")
}Swift 5.7 added a shorthand when you want the same name: if let nickname { ... }.
guard let unwraps for the rest of the function, and requires you to leave (return, break or throw) when the value is missing. It keeps the main path of a function flat, without nesting:
func greet(_ name: String?) {
guard let name else {
print("Hello, stranger")
return
}
print("Hello, \(name)")
}?? and optional chaining
The nil-coalescing operator ?? gives a default when the optional is nil:
let shown = nickname ?? "Guest"
let age = Int(input) ?? 0Optional chaining with ?. calls a property or method only if the value isn't nil; otherwise the whole expression is nil:
let length = nickname?.count // Int?
let upper = user?.address?.city?.uppercased() ?? "UNKNOWN"Chains stop at the first nil, so long chains through optional data stay short and safe.
Force unwrapping
Adding ! after an optional force unwraps it: "I'm certain there's a value". If you're wrong, the app crashes:
let n = Int("abc")! // crash: unexpectedly found nilUse ! only when nil is genuinely impossible and a crash would indicate a programming mistake, such as a resource that's always bundled with your app. In everyday code, if let, guard let and ?? are safer and just as short.
What an optional really is
An optional isn't magic. Int? is shorthand for Optional<Int>, an enum with two cases: .some(value) when there's a value and .none when there isn't. nil is simply another way to write .none:
let maybe: Int? = .some(5) // same as = 5
let nothing: Int? = .none // same as = nil
switch maybe {
case .some(let value):
print("Got \(value)") // Got 5
case .none:
print("Nothing")
}You'll rarely write .some yourself, but knowing it explains why printing an optional shows Optional(5), and why you can switch over one. A shorter pattern, case let value?:, matches only when there's a value.
Unwrapping several optionals at once
if let and guard let can unwrap several values, separated by commas, and mix in ordinary conditions. The block runs only if every unwrap succeeds and every condition is true:
let name: String? = "Ada"
let ageText: String? = "42"
if let name, let ageText, let age = Int(ageText), age >= 18 {
print("\(name) is \(age)") // Ada is 42
}Each step can use the names unwrapped before it, so Int(ageText) sees a plain String. This replaces a pyramid of nested if let blocks with a single readable line. To transform an optional without unwrapping it, map applies a function only when a value is present: Int("21").map { $0 * 2 } is Optional(42), and nil stays nil.
Swift Optionals Syntax
Optional handling
var s: String? = nil
if let s { print(s) }
if let value = s { print(value) } else { print("none") }
guard let s else { return }
let n = s ?? "default"
let len = s?.count // Int?
let x = Int("12") ?? 0
let forced = s! // crashes if nil: avoidSwift Optionals Summary
nilmeans no value; only optional types (String?) can hold it.if letandguard letunwrap optionals safely; guard requires an early exit.??supplies a default;?.calls through optionals and gives nil if any link is nil.- Functions that can fail, like Int("42"), return optionals.
!force unwraps and crashes on nil; avoid it in everyday code.
Swift Optionals Examples
Each example shows the code, the output it produces and what each part does.
if let with user input
let inputs = ["42", "seven", "", "15"]
var total = 0
for text in inputs {
if let number = Int(text) {
total += number
} else {
print("Skipping \"\(text)\"")
}
}
print("Total: \(total)")Skipping "seven"
Skipping ""
Total: 57Line-by-line explanation
- Line 5Int(text) returns Int?; if let unwraps it only when the conversion worked.
- Line 6Inside the block, number is a plain Int.
- Line 8\" puts a quote character inside the string.
guard let and ??
func describe(username: String?, age: String?) {
guard let username, !username.isEmpty else {
print("Please enter a username")
return
}
let years = Int(age ?? "") ?? 0
print("\(username) is \(years)")
}
describe(username: "ada", age: "36")
describe(username: "linus", age: nil)
describe(username: nil, age: "20")ada is 36
linus is 0
Please enter a usernameLine-by-line explanation
- Line 2guard unwraps username and also checks it isn't empty; the comma means "and".
- Lines 2 to 5If either check fails, the else block must leave the function.
- Line 6?? turns a missing age into "", and Int("") is nil, so the second ?? gives 0.
Optional chaining
struct Address { var city: String? }
struct User { var name: String; var address: Address? }
let users = [
User(name: "Ana", address: Address(city: "Lisbon")),
User(name: "Ben", address: Address(city: nil)),
User(name: "Cy", address: nil)
]
for user in users {
let city = user.address?.city?.uppercased() ?? "UNKNOWN"
print("\(user.name): \(city)")
}
print(users.first?.name ?? "No users")Ana: LISBON
Ben: UNKNOWN
Cy: UNKNOWN
AnaLine-by-line explanation
- Lines 1 to 2A struct is a simple data type you'll learn about later; address and city may be missing.
- Line 11The chain stops at the first nil, and ?? supplies a default.
- Line 14first is optional because the array could be empty.
Common Swift Optionals Mistakes
Using an optional as if it had a value
let age = Int("30")
print(age + 1) // error: value of optional type 'Int?' must be unwrappedif let age = Int("30") {
print(age + 1)
}Force unwrapping user input
let quantity = Int(textField.text!)! // crashes on empty or invalid textlet quantity = Int(textField.text ?? "") ?? 1Printing an optional directly
let nick: String? = "Addy"
print("Hi \(nick)") // Hi Optional("Addy"), with a compiler warningprint("Hi \(nick ?? "friend")")Swift Optionals in Real Projects
Optionals in apps
iOS apps handle optionals constantly: text fields whose text might be empty, images that might fail to load, results from a search that might find nothing, JSON fields that might be missing. Swift's optionals make each of those cases visible in the code, which is a big reason Swift apps crash less than apps written in languages where any value can silently be missing.
Swift Optionals FAQ
What is the difference between if let and guard let in Swift?
if let unwraps a value for use inside its own block, and code after the block can't see it. guard let unwraps it for the rest of the enclosing scope, but its else branch must leave that scope with return, break, continue or throw. Use guard for early exits at the top of a function.
What does "unexpectedly found nil while unwrapping an Optional value" mean?
It's the crash you get when ! force unwraps an optional that is nil. Find the ! on the line shown in the error and replace it with if let, guard let or ??, so the missing case is handled instead of crashing.
How do I check if an optional is nil in Swift?
Compare it directly: if value == nil { ... } or if value != nil { ... }. If you also need the value, use if let value { ... } instead, which checks and unwraps in one step.
What is an implicitly unwrapped optional?
A type written with !, such as String!, is an optional that is force unwrapped automatically each time you use it. It's mainly found in older code and Interface Builder outlets. It crashes like ! if it's nil when used, so prefer a normal optional in new code.
What does ?? do in Swift?
?? is the nil-coalescing operator. a ?? b gives the value inside a if there is one, and b otherwise, and the result isn't optional. Int(text) ?? 0 turns input that might not be a number into a plain Int with 0 as the fallback.
Swift Optionals Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the declaration so middleName can be nil.
var middleName: String = nil
What does this print?
let city: String? = nil
print(city ?? "Unknown")
What does this print?
let word: String? = "swift"
print(word?.uppercased().count ?? 0)
What must the else block of a guard let do?
When is force unwrapping with ! reasonable?
Swift Optionals Quiz
5 questions to check what you learned.
What does nil mean in Swift?
- Zero
- No value
- An empty string
- false
What type does
Int("12")return?- Int
- String
- Double
- Int?
What does
if let name { }do (Swift 5.7+)?- Unwraps the optional name into a non-optional constant with the same name
- Declares a new optional
- Sets name to nil
- Compares name with true
What does
a?.b?.cgive if b is nil?- A crash
- An empty value of c's type
- nil
- a
What happens when you force unwrap a nil value?
- The program crashes with "Unexpectedly found nil"
- It returns 0
- It returns an empty string
- It's ignored