在阅读了苹果的一些文章和开发者指南之后,我仍然对关闭捕获列表感到困惑。 它是什么意思"捕获",它在无主的自我和弱自我方面如何在幕后工作?封闭如何使用自己而不拥有对象? 我认为这就像制作该对象的副本所以当它完成时它会从堆栈中传递出来,就像值类型一样,但我想我错了。 我希望这里有人可以让它更容易理解,或者把我与一篇回答这个特定问题的好文章联系起来。 谢谢你提前
答案 0 :(得分:1)
我的理解,可能有点简化,是关于所有权和持有一个对象,这意味着只要我们声称对象的所有权,它就不能从内存中释放出来,即使是另一个部分。代码将其设置为零或类似。
使用weak
我们说可以销毁该对象,并且只有它仍然存在时我们才会使用它。
因此,当在闭包中将self
声明为weak
时,我们会说如果self
在执行闭包时仍然存在,我们通常会这样做,否则关闭将无声地被忽略而不会产生错误。
答案 1 :(得分:1)
主要与reference counting有关。在闭包内使用的任何实例(但在外部声明)都被强引用(即其引用计数递增)。这可能导致保留周期,例如
class MyClass {
var myClosure: (() -> Void)!
init() {
myClosure = {
self.foo()
}
}
func foo() {
}
}
在上面的示例中,MyClass
的实例保留对myClosure
的引用,反之亦然,这意味着MyClass
实例将永远保留在内存中。
您还可以拥有更复杂/更难点的保留周期,因此您需要真正关注,如果您有任何疑问,请为您的班级添加一些print
来电。 deinit
方法只是为了确保(或使用工具)。
为了避免这些问题,您可以将关闭时捕获的对象标记为unowned
或weak
。这意味着他们的参考计数不会增加,您可以避免这些保留周期。上面的例子可以这样做:
myClosure = { [weak self] in
self?.foo()
}
或者,更好的是这个例子,这样:
myClosure = { [unowned self] in
self.foo()
}
虽然第一种方式始终是安全的以及您更有可能做的事情,但在此示例中unowned
版本很容易推理,因为您知道myClosure
不会超过{{1} }}。但是,如果您不能100%确定self
将始终比关闭使用self
更长。
另请注意,您可以标记如何捕获闭包内使用的多个对象,只需用逗号分隔,例如
weak
答案 2 :(得分:0)
如果我们牢记默认情况下捕获的值是闭包中的强引用,则可以假定这会创建保留周期(不好的东西)。
捕获列表是可以传递给闭包的变量数组。捕获列表的目的是更改传入变量的强度。这用于中断保留周期。
例如:
// strong reference
[label = self.myLabel!] in
// weak reference
[weak label = self.myLabel!] in
// unowned reference
[unowned self] in