看一段OC代码
NSInteger i = 1;
void(^block)(void) = ^{
NSLog(@"block %ld:", i);
};
i += 1;
NSLog(@"out1 %ld:", i);
block();
NSLog(@"out2 %ld:", i);
打印
在OC里,编译器走到第三行的时候,实际上已经对i进行了拷贝,可以理解成
NSInteger iCopy = i
所以block里的值和外面的值是不会互相影响的。
如果想要里外一致,则需要通过添加 __block关键字,block里使用的变量不管是基本数据列行还是类,都会自动封装成一个对象(结构体),这个对象拥有isa指针和forwarding指针,forwarding指针指向的是自己,在ARC下block里有用到外部局部变量则会自动copy到堆,在栈区的forwarding指针就指向到堆里的isa(堆里的forwarding还是指向自己),这就打通了内外,这里不详细讨论此关键字以及循环引用相关。
看一段Swift代码
var i = 1
let closure = {
print("closure \(i)")
}
i += 1
print("out1 \(i)")
closure()
print("out 2 \(i)")
代码和OC一毛一样,打印的结果是
swift指的捕获是在执行的时候再捕获,当代码执行到 closure(),对值进行捕获,i的值是2,所以打印闭包里的i等于2
修改值
在OC里修改值基本数据类型__block, OC-Obj类型__weak。
在Swift里,看如下代码
var i = 1
let closure = {
i += 1
print("closure \(i)")
}
i += 1
print("out1 \(i)")
closure()
print("out 2 \(i)")
在闭包里多了一行 i += 1 编译,没有警告,运行结果如下
也就是说,在swift里,闭包就像是oc给外部变量默认添加了block或者__weak
Swift里实现和OC一样的值捕获,这种实现在Swift里叫捕获列表,capturing list
看如下代码
var i = 1
let closure = {
[i] in
print("closure \(i)")
}
i += 1
print("out1 \(i)")
closure()
print("out 2 \(i)")
闭包内部多了一行[i] in 语法为中括号[]里面添加捕获的变量,然后用in 分割上下分。打印结果为
类似于刚开始的OC代码,Swift内部,类似执行了这样的一行代码
let iCopy = i
最后
大家都说Swift里的闭包和OC里的block一样,在值的捕获这里是有很大的不一样的。