Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The defer statement is a control flow construct that schedules a block of code to be executed immediately before the current lexical scope exits. Regardless of how the scope is terminated—whether through a return, a thrown error, a break, or reaching the natural end of the block—the deferred code is guaranteed to run.
defer {
    // Statements to execute upon scope exit
}

Execution Mechanics

Evaluation Requirement A defer statement must be evaluated during runtime for its block to be scheduled. If the program transfers control out of the scope before reaching the defer statement, the deferred code will not execute.
func evaluationExample(shouldExitEarly: Bool) {
    if shouldExitEarly {
        return
    }
    
    defer {
        print("This only runs if shouldExitEarly is false.")
    }
}
LIFO Execution Order When multiple defer statements are declared within the same scope, they are pushed onto an execution stack. Upon scope exit, they are executed in Last-In-First-Out (LIFO) order. The last defer block evaluated is the first one executed.
func lifoExample() {
    defer { print("Deferred 1") }
    defer { print("Deferred 2") }
    defer { print("Deferred 3") }
}
// Output upon exit:
// Deferred 3
// Deferred 2
// Deferred 1

Scope Boundaries

A defer block is bound to its immediate enclosing scope, not necessarily the enclosing function. If placed inside a do block, a while loop, or an if statement, the deferred code executes as soon as that specific block terminates.
func scopeExample() {
    do {
        defer { print("Exiting do block") }
        print("Inside do block")
    } // The defer block executes here
    
    print("Outside do block")
}

Variable Capture and Evaluation

Variables referenced inside a defer block are captured by reference. The defer block reads the current value of the variables at the exact moment of execution (scope exit), not at the moment the defer statement was declared.
func captureExample() {
    var step = 1
    
    defer {
        print("Final step value: \(step)")
    }
    
    step += 1
    step += 1
}
// Output: Final step value: 3
Interaction with Return Values When a scope exits via a return statement, the return expression is evaluated before the defer block executes. Consequently, if a defer block modifies a local variable that has already been evaluated for return, that modification will not alter the function’s actual return value.
func returnExample() -> Int {
    var score = 10
    
    defer { 
        score += 5 
    }
    
    return score // Evaluates to 10 before the defer block runs. The function returns 10, not 15.
}

Compiler Restrictions

To maintain predictable control flow, the Swift compiler enforces strict limitations on the contents of a defer block:
  1. No Outward Control Transfer: You cannot transfer control out of a defer block. Statements like return, break, or continue are prohibited if they attempt to exit the defer scope itself. However, using these statements is perfectly valid if their control flow is entirely contained within the defer block (e.g., using break inside a loop that exists solely within the defer, or using return to exit a closure defined inside the defer).
  2. No Asynchronous Operations: A defer block executes synchronously upon scope exit. Consequently, it cannot contain asynchronous operations (await). Attempting to suspend execution within a defer block will result in a compiler error.
  3. No Unhandled Errors: You cannot throw an error that propagates out of a defer block. Any error thrown inside must be caught and handled within that same defer block.
Master Swift with Deep Grasping Methodology!Learn More