Tricky output-based questions on Closures — Part I
2 min readMay 1, 2024
var closures: [() -> Void] = []
for i in 0..<3 {
closures.append {
print(i)
}
}
for closure in closures {
closure()
}
Output Explanation:
- This code snippet creates an array of closures that each print the current value of
i
. - However, due to the closure-capturing behavior in Swift, all closures will capture and share the same
i
variable. - At the time the closures are executed, the value of
i
will be3
because it's the value that completes the loop. - So, the output will be:
3 3 3
.
func delayPrint() {
for i in 1...3 {
DispatchQueue.main.asyncAfter(deadline: .now() + Double(i)) {
print(i)
}
}
}
delayPrint()
Output Explanation:
- This code schedules three closures to print the value of
i
after a delay of1
,2
, and3
seconds respectively. - However, the loop completes execution before the closures execute, and at that time,
i
will be4
. - So, when the closures execute, they will all print
4
. - The output will not be in sequential order due to the asynchronous nature of
DispatchQueue.main.asyncAfter
. - Possible output could be:
4 4 4
.
var numbers = [1, 2, 3, 4, 5]
var doubledNumbers = numbers.map { $0 * 2 }
numbers[0] = 10
print(doubledNumbers)
Output Explanation:
- The
map
function creates a new array (doubledNumbers
) by applying the closure to each element of the original array (numbers
). - However,
map
creates a copy of the array elements, not a reference. - So, modifying
numbers
after creatingdoubledNumbers
doesn't affect the elements indoubledNumbers
. - Therefore, the output will be:
[2, 4, 6, 8, 10]
.
var result: Int?
let closure1 = { result = 10 }
let closure2 = { [result] in print(result) }
closure1()
closure2()
Output Explanation:
closure1
captures and modifies theresult
variable.closure2
capturesresult
as a constant at the time of its creation.- When
closure1
is called, it setsresult
to10
. - When
closure2
is called, it prints the captured value ofresult
, which isnil
because it was captured beforeclosure1
executed. - So, the output will be:
nil
.
func makeCounter() -> () -> Int {
var count = 0
return {
count += 1
return count
}
}
let counter1 = makeCounter()
let counter2 = makeCounter()
print(counter1())
print(counter2())
print(counter1())
print(counter2())
Output Explanation:
- The
makeCounter
function returns a closure that increments and returns a counter value. - Each call to
makeCounter
creates a new instance of thecount
variable. counter1
andcounter2
are two separate closures with their own instances ofcount
.- So, the output will be:
1
,1
,2
,2
.