typealias IntMaker = (Void)->Int
func makeCounter() ->IntMaker{
var n = 0 // Line A
func adder()->Integer{
n = n + 1
return n
}
return adder
}
let counter1 = makeCounter()
counter1() // returns 1
counter1() // returns 2
counter1() // returns 3
Isn't 'Line A' called each time we call counter1()
? meaning that var n = 0
should be called every time...
Why is that the counter returns different values? Shouldn't they always be returning '1' ?
Capturing Values. 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, closures capture the variables they reference: variables declared outside of the closure but that you use inside the closure are retained by the closure by default, to ensure they are still alive when the closure is executed.
A capture list is defined after the opening curly brace and before the parameter list and return type of the closure. An element of a capture list is the weak or unowned keyword followed by the reference to a class instance. In this example, we use a capture list to weakly capture self in the closure.
An instance of a closure can be passed around your code and executed without any knowledge of its internals. That makes them perfect for asynchronous development. A typical use case is when you specify the code that should execute upon the return of an asynchronous operation, and pass it as its parameters.
Obviously, Line A isn't being called each time counter1
is called.
The sequence of events is:
makeCounter
is called, which declares and initializes n
(Line A), defines adder
, and returns adder
in a context that includes n
already having been defined and initialized to 1.
It is this function that was just returned that is assigned to counter1
. Because the Line A is not part of that function (adder
/counter1
), it does not get executed when that function is called.
Each call to counter1
is executed in that same context, which is why n
retains its value across calls: they are all accessing the same n
.
You've called makeCounter()
once. That creates your new closure, and assigns it to counter1
. This closure closes over the mutable var n
, and will remain captured as long as this closure exists.
Calling counter1()
will execute it, but it retains the same captured n
, and mutates it. This particular "adder" will ALWAYS capture this same n
, so long as it exists..
To get the behavior you're suggesting, you need to make new closures which capture new instances of n
:
let counter1 = makeCounter()
counter1() // returns 1
counter1() // returns 2
counter1() // returns 3
var counter2 = makeCounter()
counter2() // returns 1
counter2 = makeCounter()
counter2() // returns 1
counter2 = makeCounter()
counter2() // returns 1
Now both counter1
and counter2
each have their own separate instances of n
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With