Lesson 19Control Flow

Guard Statement

Early Exit Pattern

The guard statement checks a condition and exits early if it's false. It's great for validation and unwrapping optionals!

Basic Syntax

guard condition else {
    // handle failure
    return // must exit!
}
// continue with valid data

Guard vs If-Let

if let

  • Variable only inside { }
  • Good for optional work
  • Nested code (pyramid)

guard let

  • Variable available after
  • Great for validation
  • Flat, readable code

Guard Must Exit

Important!

The else block must exit the current scope using:

  • return - exit function
  • break - exit loop
  • continue - next iteration
  • throw - throw error

Common Use Cases

Validation

Check input early

📦

Unwrapping

Safe optional access

🚫

Requirements

Check preconditions

main.swift
// Guard for early exit
func greet(name: String?) {
    guard let unwrappedName = name else {
        print("No name provided!")
        return
    }

    // unwrappedName is available here
    print("Hello, \(unwrappedName)!")
}

greet(name: "Alice")  // Hello, Alice!
greet(name: nil)       // No name provided!

// Guard with multiple conditions
func processUser(name: String?, age: Int?) {
    guard let userName = name,
          let userAge = age,
          userAge >= 0 else {
        print("Invalid user data!")
        return
    }

    print("\(userName) is \(userAge) years old")
}

processUser(name: "Bob", age: 25)    // Bob is 25 years old
processUser(name: nil, age: 25)       // Invalid user data!
processUser(name: "Bob", age: -5)     // Invalid user data!

// Guard vs If-Let comparison
func processWithIf(value: Int?) {
    if let number = value {
        // number only available inside this block
        print("Got: \(number)")
    }
    // number not available here!
}

func processWithGuard(value: Int?) {
    guard let number = value else {
        print("No value!")
        return
    }
    // number available for the rest of the function!
    print("Processing \(number)...")
    print("Still using \(number)!")
}

// Guard for validation
func validatePassword(_ password: String) -> Bool {
    guard password.count >= 8 else {
        print("Password too short!")
        return false
    }

    guard password.contains(where: { $0.isNumber }) else {
        print("Password needs a number!")
        return false
    }

    guard password.contains(where: { $0.isUppercase }) else {
        print("Password needs uppercase!")
        return false
    }

    print("Password is valid!")
    return true
}

validatePassword("abc")           // Too short
validatePassword("abcdefgh")      // Needs number
validatePassword("abcd1234")      // Needs uppercase
validatePassword("Abcd1234")      // Valid!

// Guard in loops
let scores = [85, -5, 92, 78, -3, 88]

for score in scores {
    guard score >= 0 else {
        print("Invalid score: \(score)")
        continue
    }
    print("Valid score: \(score)")
}

Try It Yourself!

Write a function that takes optional name and age, uses guard to validate both exist and age is positive, then prints a greeting!