Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capture list in Swift

Tags:

ios

swift

I have an example:

class Animal {
    var stamina = 0

    func increaseStamina() {
        stamina += 1
    }
}

var a = Animal()

var closure = { [weak a] in
    a?.stamina = 10
}

a.stamina // 0
a.increaseStamina()
a.stamina // 1
closure()
a.stamina // 10

if I change the closure like this:

var closure = { [weak a] in
    a = Animal()
    a?.stamina = 10
}

then it prints something like this:

a.stamina // 0
a.increaseStamina()
a.stamina // 1
closure()
a.stamina // 1

Why is the last line different?

like image 441
Khuong Avatar asked Sep 13 '16 08:09

Khuong


1 Answers

All entries in the capture list create a local variable in the closure. It is initialized with the value of the variable with the same name in the outer context, but can be modified independently.

In your case

var closure = { [weak a] in
    a = Animal()
    a?.stamina = 10
}

a inside the closure is initialized with a weak reference to the Animal object created before, but it is independent of the outer a variable. a = Animal() creates a new instance and assigns the reference to that local variable a. Because it is a weak reference, the object is deallocated immediately (you can verify that by adding print(a) in the closure). The outer variable a still references the original object:

print(a.stamina) // 0
a.increaseStamina()
print(a.stamina) // 1
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100a03060)
closure()
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100a03060)
print(a.stamina) // 1

If you omit the capture list then a inside the closure and outside the closure refer to the same variable, and a new instance can be assigned inside the closure:

var a = Animal()

var closure = {
    a = Animal()
    a.stamina = 10
}

print(a.stamina) // 0
a.increaseStamina()
print(a.stamina) // 1
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100b06ac0)
closure()
print(ObjectIdentifier(a)) // ObjectIdentifier(0x0000000100e00070)
print(a.stamina) // 10

For more information and details, see "Capture Lists" in the Swift references (thanks so @Arthur for providing the link).

like image 112
Martin R Avatar answered Oct 06 '22 08:10

Martin R