0
0
Swiftprogramming~5 mins

Capture lists in closures in Swift

Choose your learning style9 modes available
Introduction

Capture lists help control how variables are used inside closures. They let you decide if variables are kept as copies or references.

When you want to keep a snapshot of a variable's value inside a closure.
When you want to avoid strong reference cycles between closures and objects.
When you want to control if a variable is captured as a strong or weak reference.
When you want to improve memory management by preventing retain cycles.
When you want to use a variable inside a closure but keep it from changing outside.
Syntax
Swift
let closure = { [captureList] in
    // closure body
}

The capture list is inside square brackets before the in keyword.

You can capture variables as strong, weak, or unowned references.

Examples
This captures value as a copy. Changing value after does not affect the closure.
Swift
var value = 10
let closure = { [value] in
    print("Captured value is \(value)")
}
value = 20
closure()
This uses a weak capture to avoid a strong reference cycle. After person is set to nil, the closure knows the object is gone.
Swift
class Person {
    var name = "Alice"
    lazy var printName: () -> Void = { [weak self] in
        if let strongSelf = self {
            print("Name is \(strongSelf.name)")
        } else {
            print("Person no longer exists")
        }
    }
}
var person: Person? = Person()
person?.printName()
let printClosure = person!.printName
person = nil
printClosure()
unowned capture assumes the variable will always exist when the closure runs. Use carefully to avoid crashes.
Swift
class Example {
    var count = 0
    lazy var increment = { [unowned self] in
        print("Count is \(self.count)")
    }
}
Sample Program

This program shows how a closure captures self weakly to avoid memory problems. It increments a count and prints it. After the counter is set to nil, the closure safely detects it.

Swift
class Counter {
    var count = 0
    lazy var incrementClosure: () -> Void = { [weak self] in
        guard let strongSelf = self else {
            print("Counter no longer exists")
            return
        }
        strongSelf.count += 1
        print("Count is now \(strongSelf.count)")
    }
}

var counter: Counter? = Counter()
print("Before increment: \(counter?.count.map(String.init) ?? \"nil\")")
counter?.incrementClosure()
counter?.incrementClosure()
let incrementClosure = counter!.incrementClosure
print("After increments: \(counter?.count.map(String.init) ?? \"nil\")")
counter = nil
incrementClosure()
OutputSuccess
Important Notes

Time complexity: Capturing variables does not add extra time cost to closure execution.

Space complexity: Captured variables are stored inside the closure, which uses some memory.

Common mistake: Forgetting to use [weak self] can cause memory leaks by keeping objects alive.

Use capture lists when you want to control how variables are stored inside closures, especially to avoid retain cycles.

Summary

Capture lists let you control how variables are saved inside closures.

Use [weak self] or [unowned self] to avoid memory problems.

Captured variables can be copies or references depending on your needs.