Closures are reference types in Swift - Time & Space Complexity
When working with closures in Swift, it's important to understand how their reference nature affects performance.
We want to see how the cost of using closures grows as we create or call more of them.
Analyze the time complexity of the following code snippet.
func makeIncrementer(amount: Int) -> () -> Int {
var total = 0
let incrementer: () -> Int = {
total += amount
return total
}
return incrementer
}
let incrementByTen = makeIncrementer(amount: 10)
for _ in 1...n {
_ = incrementByTen()
}
This code creates a closure that adds a fixed amount each time it is called, then calls it n times.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Calling the closure inside the loop.
- How many times: The closure is called n times, once per loop iteration.
Each time we call the closure, it performs a simple addition and returns a value.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 additions and returns |
| 100 | 100 additions and returns |
| 1000 | 1000 additions and returns |
Pattern observation: The number of operations grows directly with n, the number of times the closure is called.
Time Complexity: O(n)
This means the time to run grows in a straight line as we call the closure more times.
[X] Wrong: "Closures are simple values, so calling them many times is always constant time."
[OK] Correct: Each closure call runs code, so calling it n times means n operations, not just one.
Understanding how closures behave as reference types helps you reason about performance and memory in real apps.
What if we created a new closure inside the loop each time instead of calling the same one? How would the time complexity change?
Practice
closures are reference types in Swift?Solution
Step 1: Understand what reference types mean
Reference types mean multiple variables can point to the same instance in memory.Step 2: Apply this to closures
Since closures are reference types, assigning them copies the reference, not the code itself.Final Answer:
Multiple variables can point to the same closure instance, sharing changes. -> Option AQuick Check:
Closures share instance references [OK]
- Thinking closures always create new copies
- Confusing closures with value types like structs
- Ignoring that closures capture variables by reference
Solution
Step 1: Recall Swift closure syntax
Closures are assigned using curly braces and can be stored in variables with let or var.Step 2: Check each option
let closure = { print("Hello") } uses correct syntax: let closure = { print("Hello") }.Final Answer:
let closure = { print("Hello") } -> Option BQuick Check:
Correct closure assignment syntax [OK]
- Using := which is not Swift syntax
- Trying to declare closures like functions
- Using func keyword incorrectly for closures
var closureA = { print("Count: 0") }
var closureB = closureA
closureA = { print("Count: 1") }
closureB()Solution
Step 1: Understand closure assignment
closureB is assigned closureA's original closure printing "Count: 0".Step 2: Reassign closureA
closureA is changed to a new closure printing "Count: 1", but closureB still points to the old closure.Final Answer:
Count: 0 -> Option AQuick Check:
closureB keeps original closure [OK]
- Assuming closureB changes when closureA is reassigned
- Confusing closure references with copies
- Expecting both closures to print the same after reassignment
var closure1 = { print("Hello") }
var closure2 = closure1
closure1 = { print("World") }
closure2 = closure1Solution
Step 1: Check closure assignments
Both closure1 and closure2 are variables and can be reassigned closures.Step 2: Validate syntax and assignments
All closure assignments use correct syntax and valid variable usage.Final Answer:
No error, code runs fine -> Option CQuick Check:
Valid closure reassignment [OK]
- Thinking reassignment causes errors
- Confusing closure syntax with function syntax
- Assuming closures must be constants
func makeCounter() -> () -> Int {
var count = 0
let increment: () -> Int = {
count += 1
return count
}
return increment
}
let counter1 = makeCounter()
let counter2 = counter1
print(counter1())
print(counter2())Solution
Step 1: Understand closure capturing
The closure increments and returns the same captured variable 'count'.Step 2: Analyze reference sharing
counter1 and counter2 reference the same closure instance, so increments affect both.Step 3: Trace calls
First call counter1() returns 1, second call counter2() increments count to 2 and returns 2.Final Answer:
1 and 2 -> Option DQuick Check:
Shared closure state increments count [OK]
- Thinking counter2 is independent copy
- Ignoring closure captures and shared state
- Assuming count resets on each call
Ready to prove it?
Pass the test and this pattern moves unknown
