01. Capturing Values

It will take about 3 minutes to finish reading this article.

The capture of values in Swift’s closure and OC’s Block is different.

1. The capture of values in OC.

1
2
3
4
5
6
7
8
9
10
11
12
13
NSInteger a = 100;
void(^block)(void) = ^{
NSLog(@"block = %ld:", a);
};

a += 1;
NSLog(@"out1 = %ld:", a);
block();
NSLog(@"out2 = %ld:", a);
//result:
2021-08-17 11:27:13.846743+0800 MDProject[30746:23593763] out1 = 101
2021-08-17 11:27:13.846885+0800 MDProject[30746:23593763] block = 100
2021-08-17 11:27:13.847002+0800 MDProject[30746:23593763] out2 = 101

2. The capture of values in Swift.

1
2
3
4
5
6
7
8
var a = 100
let closure = {
print("closure = \(a)")
}
a += 1
print("out 1 = \(a)")
closure()
print("out 2 = \(a)")

Result:

1
2
3
out1 = 101
closure = 101
out 2 = 101

Swift closures capture “references”, not the objects they reference. We can print the address of variable a to prove this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var a = 100
withUnsafePointer(to: &a) {ptr in print(ptr)}
let closure = {
print("closure = \(a)")
withUnsafePointer(to: &a) {ptr in print(ptr)}
}
closure()
a += 1
print("out 1 = \(a)")
withUnsafePointer(to: &a) {ptr in print(ptr)}

closure()
print("out 2 = \(a)")
withUnsafePointer(to: &a) {ptr in print(ptr)}

Result as follows:

1
2
3
4
5
6
7
8
9
0x0000600000209490
closure = 100
0x0000600000209490
out 1 = 101
0x0000600000209490
closure = 101
0x0000600000209490
out 2 = 101
0x0000600000209490

They all have the same address, It proves that closure capture the reference of the variable, not like block in OC.

3. Modify value in closure.

If we want to modity value in block, we should add “__block” or “__weak”, that will make the block capture reference of variable from outside.
Let me see how closure handle this case.

1
2
3
4
5
6
7
8
var a = 100
let closure = {
a += 1
print("closure = \(a)")
}
print("out 1 = \(a)")
closure()
print("out 2 = \(a)")

Result:

1
2
3
out 1 = 100
closure = 101
out 2 = 101

We can modify the value of the variable in closure directly because closure capture the reference of the variable by default.

4. Capturing list in closure.

If we capture variable in capturing list in closure, what will happen? Let me see that.

1
2
3
4
5
6
7
8
9
var a = 100
let closure = {
[a] in
print("closure = \(a)")
}
a += 1
print("out 1 = \(a)")
closure()
print("out 2 = \(a)")

Result:

1
2
3
out 1 = 101
closure = 100
out 2 = 101

At this time if we want to modify ‘a’ in closure:

1
2
3
4
5
6
7
8
9
10
var a = 100
let closure = {
[a] in
a += 1
print("closure = \(a)")
}
a += 1
print("out 1 = \(a)")
closure()
print("out 2 = \(a)")

It will get an error like that:

And this is a tip for us that variable ‘a’ is an immutable capture now.