闭包解释中的强、弱和无主自我

Strong, weak and unowned self in closures explanation

我需要一些关于 Swift 中闭包引用的解释。 这是我的用例,假设我们有:

class A {...}
class B {

  func makeAclosure() {
   let instanceA = A()
   instanceA.someFunctionA(completion: {(input) in 
     self.someAnotherFunction(input)
   })
  }
}

class A 和 B 之间是否存在保留循环? 在这种情况下,在哪种情况下它可以是一个保留周期?

如果您的 self 对象可能会在您的闭包被调用之前被释放,您应该指定 [weak self],这样您就可以避免错误的访问异常。

如果您知道它绝对不会被释放,那么您可以使用[unowned self]创建一个引用,其行为类似于隐式展开的可选。

在您的示例中,B 的实例拥有对 instanceA 的引用(在您的 makeAClosure() 函数的上下文中),因此您不会以保留循环结束.

您应该考虑 someFunctionA(completion:) 的实现,以确定您是否需要在该闭包中对 selfunownedweak 引用。


(顺便说一句:如果你使用 [weak self],那么为了避免在你的代码中使用诸如 self? 之类的选项,你可以使用 guard let `self` = self else { ... }继续在关闭代码中使用 self

如果不看 A.someFunctionA 就无法判断,因为不知道 completion 是否是 @escaping(例如,它是否被保留)。对于其余的答案,我将假设它是 @escaping.

Swift 需要确保运行时安全,并且会保留它在未来可能需要的任何对象,在这种情况下通过对 self 进行强引用(因为 self是闭包内使用的唯一变量)。

在这种情况下没有引用循环。这是因为instanceA没有保留,所以A => B,而是B !=> A.

但是,如果 instanceAB 保留(假设您创建了一个 instanceA: A 属性 并设置了它),那么您将有一个保留周期。

为了解决这个问题,您可以在闭包中创建变量 weakunowned。他们都做同样的事情,但为您提供略有不同的类型。它们都持有弱引用,这意味着 instanceA 不会增加您的 B 实例的引用计数;如果 B 被释放并且没有其他引用,则 instanceA 也被释放。

当使用[weak self]selfoptional,例如self: B?。然而,[unowned self] 被显式展开,例如self: B!。这意味着如果调用闭包并且 selfnil 你的程序将会崩溃。这就是为什么只有在您确定释放 B 也会释放 A 时才使用 unowned 很重要。在某些情况下 unowned 是安全的,例如创建闭包并将其存储在创建它的同一个对象上时的情况,但这有更多细微差别。

如果不确定,请使用weak!