Swift捕获列表Capture List

闭包的特点

swift的iOS的app中,遍布着各种闭包,闭包中经常出现捕获列表,我们经常用[weak self]来防止内存泄露。我们都知道swift闭包捕获的是引用,但是swift闭包任何时候都是捕获变量的引用吗?并不是!

现在我们来看一个简单的例子:

var a = 0

var b = 0

let closure : () -> () = { print(a, b) }

执行闭包

closure()   // 0 0

改变 a, b 的值

a = 3

b = 7

再次调用

closure()  // 3 7

我们可以很直观的看到现在的a,b值都改变了。swift的闭包中捕获到的值是捕获的引用。所以一旦你改变了这些捕获变量的值,在闭包中就会反应出来。

引用类型带来的问题

事实上,很多时候,闭包的特性并不总是那么直观,如果不仔细,很容易带来一些奇怪的错误。比如,我们创建一个Array,然后数组的类型是闭包

var arrayClosure :  [() -> ()] = []

然后我们执行下面的代码,将闭包添加到数组中

var i = 0

for _ in 1...3 {

arrayClosure.append { print(i) }

 i += 1

}

我们尝试条用数组中的三个闭包来看看最后的打印值:

arrayClosure[0]()// 3

arrayClosure[1]()// 3

arrayClosure[2]()// 3

和我们预想的不太一样哈,闭包打印的值竟然都是最后一次的值。意味着三个闭包引用的都是最后一次的i的值。事实上我们想要的值或许是1,2,3。想象一下,如果三个闭包每次捕获的都是每次i的值的副本。那么是不是会打印出1,2,3的结果?但是闭包捕获的是引用呀,怎么才能获取copy副本呢。没错,就是捕获列表。

好了,现在我们再看另一个例子,看起来和开篇的第一个例子差不多,但是这里我们加了" [c, d] in " ,关键字 in 的左边就是我们的重点,这里表示的不是数组,而是捕获列表。一旦用了捕获列表,闭包捕获的将不是原始值的引用,而是在闭包内部诡异的生成了一个原始值的copy副本。

var c = 0

var d = 0

let anotherClosure : () -> () = {  [c, d]  in

print(c, d)

}

c = 3

d = 7

调用闭包,我们看看打印结果:

anotherClosure() // 0, 0

所以,显而易见,当你使用了捕获列表之后,你无论怎么在闭包外面操作改变原始的值。闭包并不关心。因为这个时候它已经不是捕获的引用了,而是最初原始值的copy副本。所以文中的第二个例子如果想得到1,2,3的结果。使用捕获列表就完全可以解决,perfect!


调用闭包得到1,2,3的结果

所以对于swift的闭包而言,并不总是捕获的引用。这篇先到这里,文笔不好,大家多多关照(*^__^*) 

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容