Closures causing retain cycles in Swift - Time & Space Complexity
When closures capture objects strongly, they can create retain cycles that keep objects alive longer than needed.
We want to understand how this affects the program's running time as more closures and objects are involved.
Analyze the time complexity of the following Swift code snippet.
class Person {
var name: String
var greet: (() -> Void)?
init(name: String) {
self.name = name
greet = { [self] in print("Hello, \(self.name)!") }
}
}
var people = [Person]()
for i in 1...n {
people.append(Person(name: "Person \(i)"))
}
This code creates n Person objects, each holding a closure that captures self strongly, potentially causing retain cycles.
Look for repeated actions that affect execution time.
- Primary operation: Creating Person objects and assigning closures inside a loop.
- How many times: The loop runs n times, creating n closures capturing self.
As n grows, the number of Person objects and their closures grows linearly.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 creations and closures |
| 100 | 100 creations and closures |
| 1000 | 1000 creations and closures |
Pattern observation: The work grows directly with n, doubling n doubles the work.
Time Complexity: O(n)
This means the time to create all objects and closures grows in a straight line as n increases.
[X] Wrong: "Closures capturing self won't affect performance or memory over time."
[OK] Correct: Strongly capturing self in closures can cause retain cycles, keeping objects alive and increasing memory and runtime unexpectedly.
Understanding how closures capture objects and affect program growth shows you can write safer, more efficient Swift code.
"What if we used [weak self] in the closure capture list? How would the time complexity change?"