Swift - Capture List自我澄清

时间:2018-05-02 07:22:40

标签: swift closures self unowned-references capture-list

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

3 个答案:

答案 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方法只是为了确保(或使用工具)。

为了避免这些问题,您可以将关闭时捕获的对象标记为unownedweak。这意味着他们的参考计数不会增加,您可以避免这些保留周期。上面的例子可以这样做:

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