Capture lists help control how variables are used inside closures. They let you decide if variables are kept as copies or references.
Capture lists in closures in 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.
value as a copy. Changing value after does not affect the closure.var value = 10 let closure = { [value] in print("Captured value is \(value)") } value = 20 closure()
person is set to nil, the closure knows the object is gone.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.class Example { var count = 0 lazy var increment = { [unowned self] in print("Count is \(self.count)") } }
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.
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()
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.
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.
Practice
Solution
Step 1: Understand what capture lists do
Capture lists let you specify how variables are captured inside closures, either by strong, weak, or unowned references.Step 2: Identify the main purpose
The main purpose is to control how variables are stored and referenced to avoid memory leaks or unexpected behavior.Final Answer:
To control how variables are stored and referenced inside the closure -> Option AQuick Check:
Capture list purpose = control variable capture [OK]
- Confusing capture lists with closure parameters
- Thinking capture lists define return types
- Assuming capture lists affect closure execution timing
Solution
Step 1: Recall capture list syntax
Capture lists are declared inside square brackets before the closure parameters, e.g., [weak self].Step 2: Match correct syntax
let closure = { [weak self] in print(self) } uses the correct syntax: [weak self] inside square brackets before the closure body.Final Answer:
let closure = { [weak self] in print(self) } -> Option CQuick Check:
Capture list syntax = [weak self] [OK]
- Omitting square brackets around capture list
- Placing 'weak' outside the brackets
- Using parentheses instead of brackets
class Example {
var value = 10
lazy var closure: () -> Void = { [unowned self] in
print(self.value)
}
}
let example = Example()
example.value = 20
example.closure()Solution
Step 1: Understand unowned self capture
The closure captures self as unowned, meaning it references the original object without increasing retain count.Step 2: Check value at closure call
example.value is updated to 20 before calling closure, so print(self.value) outputs 20.Final Answer:
20 -> Option AQuick Check:
Unowned self captures current value = 20 [OK]
- Thinking closure captures old value copy
- Confusing unowned with weak causing nil
- Expecting runtime error without object deallocation
class Test {
var count = 0
lazy var closure: () -> Void = { [weak self] in
self.count += 1
print(self.count)
}
}Solution
Step 1: Analyze weak self usage
When capturing self as weak, self becomes an optional inside the closure.Step 2: Check code for optional unwrapping
The code uses self.count directly without unwrapping, causing a compile error.Final Answer:
Cannot use weak self without unwrapping optional -> Option DQuick Check:
Weak self requires optional unwrapping [OK]
- Using weak self as non-optional
- Ignoring optional chaining or guard let
- Assuming lazy closures can't have capture lists
Solution
Step 1: Understand capture by copy
To capture a variable by making a copy, you assign it inside the capture list using syntax like [value = variable].Step 2: Evaluate options
[value = variable] uses the correct syntax to copy the variable's value into the closure's capture list.Final Answer:
[value = variable] -> Option BQuick Check:
Copy capture syntax = [value = variable] [OK]
- Using weak or unowned which capture references
- Assuming [copy variable] is valid syntax
- Not assigning variable inside capture list
Ready to prove it?
Pass the test and this pattern moves unknown
