简体   繁体   English

封闭说明中的强,弱和无主自我

[英]Strong, weak and unowned self in closures explanation

I need some explanation about references in closures in Swift. 我需要一些有关Swift闭包中引用的解释。 Here is my use case, let's imagine we have : 这是我的用例,让我们想象一下:

class A {...}
class B {

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

Is there a retain cycle between class A and B or not ? A级和B级之间是否存在保留周期? In which case it can be a retain cycle in this kind of scenario ? 在这种情况下,哪种情况可能是保留周期?

If your self object will potentially be deallocated before your closure is called, you should specify [weak self] , so that you can avoid bad access exceptions. 如果您的self对象可能在调用闭包之前被释放,则应指定[weak self] ,以免发生错误的访问异常。

If you know that it will definitely not be deallocated, then you can use [unowned self] to create a reference that will behave like an implicitly unwrapped optional. 如果您知道绝对不会释放它,则可以使用[unowned self]创建一个引用,该引用的行为类似于隐式解包的可选。

In your example, the instance of B owns the reference to instanceA (within the context of your makeAClosure() function), so you will not end up with a retain cycle. 在您的示例中, B的实例拥有对instanceA的引用(在makeAClosure()函数的上下文内),因此您不会以保留周期结束。

You should consider the implementation of someFunctionA(completion:) , to determine if you need an unowned or a weak reference to self in that closure. 您应该考虑someFunctionA(completion:)的实现,以确定在该闭包中是否需要对selfunownedweak引用。


(A small aside: if you're using [weak self] , then to avoid having optionals such as self? throughout your code, you can use guard let `self` = self else { ... } to continue using self in the closure code. (还有一点:如果您使用的是[weak self] ,则为了避免在整个代码中使用诸如self?可选参数,您可以使用guard let `self` = self else { ... }继续在代码中使用self关闭代码。

It is not possible to say without looking at A.someFunctionA since it's unknown if completion is @escaping (eg if it's retained). 如果不查看A.someFunctionA ,就无法说A.someFunctionA因为不知道completion是否在@escaping (例如,是否保留)。 For the rest of the answer I will assume that it is @escaping . 对于其余的答案,我将假定它为@escaping

Swift needs to ensure runtime safety, and will keep any objects it might need in the future alive, in this case by making a strong reference to self (since self is the only variable used inside the closure). Swift需要确保运行时的安全性,并通过强烈引用self来保持将来可能需要的所有对象处于活动状态(因为self是闭包内部唯一使用的变量)。

In this scenario there is no reference cycle . 在这种情况下,没有参考周期 This is because instanceA is not retained, so A => B, but B !=> A. 这是因为没有保留instanceA ,所以A => B,但是B!=>A。

However, if instanceA was retained by B (let's say you create an instanceA: A property and set it) then you will have a retain cycle. 但是,如果instanceAB保留(假设您创建一个instanceA: A属性并进行设置),那么您将拥有一个保留周期。

To get around this you can make variables within the closure either weak or unowned . 为了解决这个问题,您可以在闭包中使变量变weak或不具有unowned They both do the same thing, but provide you with slightly different types. 它们都做相同的事情,但是为您提供的类型略有不同。 They both hold a weak reference, meaning that instanceA will not be increase the reference count of your B instance; 它们都具有弱引用,这意味着instanceA不会增加B实例的引用计数; if B is deallocated and there are no other reference, instanceA is also deallocated. 如果B被释放并且没有其他引用,则instanceA也被释放。

When using [weak self] self is optional , eg self: B? 当使用[weak self] selfoptional ,例如self: B? . However, [unowned self] is explicitly unwrapped, eg self: B! 但是, [unowned self]已显式展开,例如self: B! . This means that if the closure is called and self is nil your program will crash. 这意味着,如果调用了闭包并且selfnil您的程序将崩溃。 This is why it's important to only use unowned when you know for certain that deallocating B will also deallocate A . 这就是为什么在确定要释放B也会释放A时,仅使用unowned的重要性。 There are a few scenarios where unowned is safe, eg the case when creating a closure and storing it on the same object that created it, but there are more nuances to this. 在某些情况下, unowned是安全的,例如创建闭包并将其存储在创建闭包的同一对象上的情况,但是对此存在更多细微差别。

If unsure, use weak ! 如果不确定,请使用weak

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM