12.3 Capturing Values
A closure can capture constants and variables from the surrounding context in which it is defined. It can then refer to those constants and variables in its body, even if the original scope no longer exists.
In Swift, the simplest version of a closure that captures values is a nested function. For example, the following incrementor()
function captures two parameters, amount
and runningTotal
:
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
The total makeIncrementor(forIncrement: Int)
function returns a function of type () -> Int
. It takes no parameters, but is able to increment the runningTotal
parameter repeatedly, as shown:
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
It does this by capturing a reference to the amount
and runningTotal
parameters when it is first called. This gives it access to the parameters long after the initial makeIncrementor
function has finished executing.
NOTE
As an optimization, Swift may instead capture and store a copy of a value if that value is not mutated by a closure, and if the value is not mutated after the closure is created.
Swift also handles all memory management involved in disposing of variables when they are no longer needed.