Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Swift Dictionary

  1. Home
  2. Swift Dictionary
  3. @escaping / @autoclosure / Capture List

@escaping / @autoclosure / Capture List

In Swift, @escaping is an annotation for closures that outlive the function scope. @autoclosure automatically wraps an argument expression into a closure, and capture lists prevent retain cycles.

Syntax

// @escaping: closure stored or called after the function returns
func functionName(completion: @escaping () -> Void) {
    DispatchQueue.main.async {
        completion()  // called after the function has returned
    }
}

// @autoclosure: automatically wraps an argument into a closure
func functionName(_ condition: @autoclosure () -> Bool) { }
functionName(x > 0)  // equivalent to { x > 0 }

// Capture list (prevents retain cycles)
{ [weak self, unowned obj] in
    self?.method()
}

Syntax List

SyntaxDescription
@escapingIndicates that the closure may be stored or called after the function returns.
@autoclosureAutomatically wraps the argument expression into a closure, enabling lazy evaluation.
[weak self]Captures self as a weak reference. Use this when self may become nil.
[unowned self]Captures self as an unowned reference. Use this only when self is guaranteed to be alive.
[weak obj]Captures an arbitrary object as a weak reference.
self?.method()Unwraps the weak self reference and calls a method on it.

Sample Code

import Foundation

// @escaping example (callback for asynchronous processing)
var completionHandlers: [() -> Void] = []

func addHandler(_ handler: @escaping () -> Void) {
    completionHandlers.append(handler)  // stored outside the function scope
}

addHandler { print("Handler 1 executed") }
addHandler { print("Handler 2 executed") }
completionHandlers.forEach { $0() }

// @autoclosure example (enabling short-circuit evaluation)
func logIf(_ condition: @autoclosure () -> Bool, message: String) {
    if condition() {
        print("[LOG] \(message)")
    }
}

let value = 42
logIf(value > 0, message: "Positive value")   // value > 0 is wrapped into a closure
logIf(value < 0, message: "Negative value")   // not evaluated if condition is false

// Preventing retain cycles with a capture list
class ViewController {
    var name = "Main Screen"

    func setupTimer() {
        // Use [weak self] to prevent a retain cycle
        Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] _ in
            guard let self = self else { return }
            print("\(self.name) timer fired")
        }
    }
}

// Capturing a value type (captured by copy)
var counter = 0
let captureByValue = { [counter] in
    print("Value at capture time: \(counter)")
}
counter = 100
captureByValue()  // prints the value at capture time (0)
print("Current value: \(counter)")

Notes

You must mark a closure with @escaping when it is stored as a property or called asynchronously. Omitting it causes a compile error.

When you use a closure inside a class method and reference self within the closure, be careful about retain cycles. Capture self with [weak self] and always unwrap it with self?. or guard let self = self. Use [unowned self] only when you can guarantee that self will always be alive.

For the basics of closures, see Closures (Basics) / { } / in.

If you find any errors or copyright issues, please .