【问题标题】:Strong, weak and unowned self in closures explanation闭包中的强、弱和无主自我解释
【发布时间】:2017-09-26 11:20:12
【问题描述】:

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

class A {...}
class B {

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

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

【问题讨论】:

    标签: swift closures automatic-ref-counting


    【解决方案1】:

    不看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

    【讨论】:

    • 感谢您的回答!只是为了确认,所以当我在 B 类的函数中创建 instanceA : A 时,它只在函数的上下文中考虑,而不是类的引用?进行强引用的唯一方法是使 instanceA: A 成为 B 类的属性?还有一个问题,如果我不放@escaping,闭包不会保留自我?
    • 是的,在这种情况下,instanceA 仅保留在内存中,直到它不再被任何地方引用,即一旦 makeAclosure 完成执行。是的,阻止instanceA 被释放的唯一方法是保持对它的强引用,例如将其设置为B 的属性。如果您不输入@escaping,编译器将不允许您存储传入的闭包。在没有@escaping 的情况下开始并等待编译器抱怨!
    【解决方案2】:

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

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

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

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


    (小题外话:如果你使用[weak self],那么为了避免在你的代码中出现self? 之类的选项,你可以使用guard let `self` = self else { ... } 在闭包代码中继续使用self .

    【讨论】:

    • 这是不正确的。在这种情况下,您将没有保留循环,因为常量 instanceA 是在函数内部创建的。
    • 感谢您的回答!只是为了确认,所以当我在 B 类的函数中创建 instanceA : A 时,它只在函数的上下文中考虑,而不是类的引用?进行强引用的唯一方法是使 instanceA: A 成为 B 类的属性?
    • @Alex 哎呀!我将编辑答案以删除该部分。其余部分仍然有效,所以我将其留在那里。
    • 太棒了!不用担心,除了你的回答很好:)
    猜你喜欢
    • 2012-03-04
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多