After reading this post, I have felt that the following question is not adequately exaplained in TSPL.
How does a closure capture local variables by reference?
TSPL provides an excellent example but doesn't really explain the mechanics of capturing by reference.
From TSPL:
A closure can capture constants and variables from the surrounding context in which it’s defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.
In Swift, the simplest form of a closure that can capture values is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.
Here’s an example of a function called
makeIncrementer
, which contains a nested function calledincrementer
. The nestedincrementer()
function captures two values,runningTotal
andamount
, from its surrounding context. After capturing these values,incrementer
is returned bymakeIncrementer
as a closure that incrementsrunningTotal
byamount
each time it’s called.
func makeIncrementer(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementer() -> Int { runningTotal += amount return runningTotal } return incrementer }
When considered in isolation, the nested
incrementer()
function might seem unusual:func incrementer() -> Int { runningTotal += amount return runningTotal }
The
incrementer()
function doesn’t have any parameters, and yet it refers torunningTotal
andamount
from within its function body. It does this by capturing a reference torunningTotal
andamount
from the surrounding function and using them within its own function body. Capturing by reference ensures thatrunningTotal
andamount
don’t disappear when the call tomakeIncrementer
ends, and also ensures thatrunningTotal
is available the next time theincrementer
function is called.
Someone, after reading the passage above, may still wonder: But, after the func makeIncrementer
returns, the local variable allocated on the stack goes out of scope and is destroyed. Then, how can the closure still reference that variable?
They might ask: How does a closure capture local variables by reference? What are the mechanics of it?
The question is answered in sufficient details by this post, thanks to @Jumhyn.