SyntaxStudy
Sign Up
Swift Beginner 1 min read

Closure Syntax

Closures are self-contained blocks of functionality that can capture values from their surrounding context. Swift closures have concise syntax — trailing closure syntax, type inference, shorthand argument names ($0, $1), and implicit return for single-expression closures. Closures capture variables by reference from their surrounding scope. This is called a closing over values. The @escaping attribute marks closures that outlive the function they were passed to. Autoclosures (@autoclosure) wrap an expression in a closure automatically, enabling lazy evaluation of arguments.
Example
// Full closure syntax
let multiply: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in
    return a * b
}

// Type-inferred shorthand
let multiply2: (Int, Int) -> Int = { a, b in a * b }

// Shorthand argument names
let multiply3: (Int, Int) -> Int = { $0 * $1 }

// Trailing closure syntax
let numbers = [5, 3, 8, 1, 9, 2]
let sorted = numbers.sorted { $0 < $1 }

// Capturing values
func makeCounter(start: Int = 0) -> () -> Int {
    var count = start
    return { count += 1; return count }
}
let counter = makeCounter()
print(counter())  // 1
print(counter())  // 2
print(counter())  // 3

// @escaping closure
class DataLoader {
    var completions: [() -> Void] = []

    func loadData(completion: @escaping () -> Void) {
        completions.append(completion)  // escapes the function
    }
}

// @autoclosure - lazy evaluation
func logIfDebug(_ message: @autoclosure () -> String) {
    #if DEBUG
    print(message())  // only evaluated in debug builds
    #endif
}
logIfDebug("Expensive computation: \(Array(1...1000).reduce(0, +))")