block和闭包对值的捕获差异

OC的block对外部变量的捕获

OC中,block捕获的值是block**初始化时上下文**中变量的瞬时值,也就是一个常量

1
2
3
4
5
6
7
8
9
10
-(void)testBlock {
NSInteger i = 1;
void(^block)(void) = ^{
NSLog(@"block %ld", i);
}
i += 1;
NSLog(@"before block %ld", i); // 2
block(); // 1
NSLog(@"after block %ld", i); // 2
}

捕获__block修饰的变量时,将变量捕获到堆区,外部的修改会影响内部捕获的值(其实是捕获了内存地址)

1
2
3
4
5
6
7
8
9
10
-(void)testBlock {
__block NSInteger i = 1;
void(^block)(void) = ^{
NSLog(@"block %ld", i);
}
i += 1;
NSLog(@"before block %ld", i); // 2
block(); // 2
NSLog(@"after block %ld", i); // 2
}

Swift中闭包对外部变量的捕获

闭包——捕获了上下文的常量或者变量的函数

swift中的闭包对变量的捕获分为两种情况:捕获值和捕获列表

  • 捕获值:在执行时捕获

  • 捕获列表:在闭包初始化时捕获上下文中的常量和变量,捕获列表的值不可变;捕获列表一般用于解决循环引用

捕获值示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func closure1() {
var i = 1
let closure = {
i += 1
print(i)
}
i += 1
print("before closure: \\(i)")
closure()
print("after closure: \\(i)")
}

closure1()
// 打印结果:
before closure: 2
3
after closure: 3

捕获值示例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func closure2() {
var i = 1
let closure = {
print("closure \\(i)")
}
i += 1
closure()
i += 1
closure()
i += 1
closure()
}

closure2()
// 打印结果
closure 2
closure 3
closure 4

捕获列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func closure3() {
var a = 0;
var b = "xxx";
let closure = { [a, b] in
print("closure a:\(a) \nclosure b:\(b)")
}
a = 1
b = "yyy"
closure()
}

closure3()
// 打印结果:
closure a:0
closure b:xxx