Swift Guard Statement
A guard statement checks a condition and exits the current scope when the condition fails. It protects the rest of your code from bad input. Swift developers use it at the top of a function to reject invalid data early and keep the main logic clean.
Imagine a security guard at the entrance of a concert hall. The guard checks your ticket at the door. Visitors without a ticket leave right away, and visitors with a ticket walk inside and enjoy the show. A guard statement follows the same plan.
Basic Syntax
guard condition else {
// runs when the condition is false
// must leave the scope
}
// code here runs only when the condition is trueThe else block must leave the current scope. Swift accepts return, break, continue, throw, or a call to a function that never returns, such as fatalError.
Diagram: Guard Flow
+-------------------+
Start --> guard condition ? |
+----+---------+----+
| |
false true
| |
v v
+-----------+ +--------------+
| else | | main logic |
| block: | | continues |
| return | | below |
+-----------+ +--------------+Guard With a Simple Condition
func checkAge(_ age: Int) {
guard age >= 18 else {
print("Access denied")
return
}
print("Access granted")
}
checkAge(20) // Output: Access granted
checkAge(15) // Output: Access deniedGuard Let for Optionals
The pattern guard let unwraps an optional value. The unwrapped constant stays available after the guard statement, which makes it different from if let.
func showName(_ name: String?) {
guard let name = name else {
print("No name provided")
return
}
print("Hello, \(name)")
}
showName("Mia") // Output: Hello, Mia
showName(nil) // Output: No name providedSwift 5.7 and later accepts the shorter form guard let name else.
Guard Versus Nested If
Nested if statements push the main logic deeper into the code. Developers call this shape the pyramid of doom. Guard statements flatten the structure.
// Nested style
func greet(name: String?) {
if let name = name {
if !name.isEmpty {
print("Hi, \(name)")
}
}
}
// Guard style
func greetSafely(name: String?) {
guard let name = name, !name.isEmpty else { return }
print("Hi, \(name)")
}The guard version reads from top to bottom. Each line removes one problem, and the final line holds the successful path.
Example: Account Registration
A signup function often checks several rules. Each guard statement handles one rule and prints a clear message.
func register(name: String?, age: Int?) {
guard let name = name, !name.isEmpty else {
print("Name is missing")
return
}
guard let age = age, age >= 13 else {
print("Age must be 13 or above")
return
}
print("Welcome, \(name). Age: \(age)")
}
register(name: "Mia", age: 20) // Output: Welcome, Mia. Age: 20
register(name: "", age: 20) // Output: Name is missing
register(name: "Leo", age: 9) // Output: Age must be 13 or aboveGuard Inside Loops
The continue keyword inside a guard block skips the current loop item and moves to the following one.
let scores = [80, -1, 95, -5, 70]
for score in scores {
guard score >= 0 else { continue }
print("Valid score: \(score)")
}
// Output:
// Valid score: 80
// Valid score: 95
// Valid score: 70When to Use Guard
- Validate function parameters at the top of the function.
- Unwrap optionals that the rest of the function needs.
- Skip bad items inside a loop.
- Stop work when a required resource is missing.
Choose if when both outcomes carry equal importance. Choose guard when one outcome is a failure that should end the work.
Writing Helpful Messages
A guard failure should tell the user or the developer what went wrong. Short, direct messages such as "Age must be 13 or above" beat vague text such as "Error". Functions that return a value usually send back nil or throw an error, and printing alone suits small examples only.
Common Mistakes
The else block of a guard statement must leave the scope. A block that only prints a message produces a compile error, because Swift cannot continue safely. Add return, continue, break, or throw at the end of the block.
Shadowing a name with guard let name = name is legal and common. Beginners sometimes worry about the repeated name. Swift treats the new constant as the unwrapped version, and the original optional stays hidden for the rest of the scope.
Real-World Use
Form screens validate email, password, and age with a stack of guard statements. Network code checks for a valid web address, a successful response, and readable data in separate guard lines. Each line removes one risk, and the final lines handle the healthy result.
Key Takeaways
- The
elseblock of a guard statement must exit the scope. - Values unwrapped by
guard letremain available after the statement. - Guard statements remove deep nesting and show the happy path clearly.
