1

在阅读了一些苹果的文章和开发者指南之后,我仍然对关闭捕获列表感到困惑。“捕获”是什么意思,在无主自我和弱自我方面如何在幕后工作?闭包如何在不拥有对象的情况下使用 self?我认为它就像制作该对象的副本,所以当它完成时,它会像值类型一样从堆栈传递,但我想我错了。我希望这里的某人可以使它更容易理解,或者将我链接到回答这个特定问题的好文章。感谢提前

4

3 回答 3

1

它主要与引用计数有关。任何在闭包内部使用(但在外部声明)的实例都被强引用(即它的引用计数增加)。这可能导致保留周期,例如

class MyClass {
    var myClosure: (() -> Void)!

    init() {
        myClosure = {
            self.foo()
        }
    }

    func foo() {
    }
}

在上面的例子中,实例MyClass保留了对的引用,myClosure反之亦然,这意味着MyClass实例将永远留在内存中。

您还可以有更复杂/更难发现的保留周期,因此您需要真正注意,如果您有任何疑问print,请在您的类方法中添加一些调用,deinit以确保(或使用仪器)。

为了避免这些问题,您可以将在闭包中捕获的对象标记为unownedweak。这意味着它们的引用计数不会增加,您可以避免这些保留周期。上面的示例可以通过这种方式完成:

myClosure = { [weak self] in
    self?.foo()
}

或者,对于这个例子来说更好的是,这样:

myClosure = { [unowned self] in
    self.foo()
}

虽然第一种方法总是安全的,而且您更有可能这样做,但unowned在此示例中该版本很容易推理,因为您知道它myClosure不会超过self. 但是,如果您不能 100% 确定这self将永远比闭包寿命长,请使用weak.

另请注意,您可以标记如何捕获闭包内使用的多个对象,只需用逗号分隔即可,例如

myClosure = { [weak self, unowned bar] in
    self?.foo(bar)
}
于 2018-05-02T07:45:26.563 回答
1

我的理解(可能有点简化)是关于所有权和对对象的持有,这意味着只要我们声明对象的所有权,它就不能从内存中释放,即使代码的另一部分设置它为零或类似。

weak我们说可以销毁对象,并且我们只会在它仍然存在的情况下使用它。

因此,当在闭包中声明时selfweak我们说如果self在执行闭包的时候仍然存在,我们通常会这样做,否则闭包将被默默地忽略而不会产生错误。

于 2018-05-02T07:44:39.650 回答
0

如果我们记住默认情况下捕获的值是闭包中的强引用,我们可以假设这会创建保留循环(坏东西)。

捕获列表是可以传递给闭包的变量数组。捕获列表的目的是改变传入变量的强度。这用于打破保留循环。

例如:

// strong reference
[label = self.myLabel!] in

// weak reference
[weak label = self.myLabel!] in

// unowned reference
[unowned self] in
于 2020-09-16T04:40:05.553 回答