2017-09-26 83 views
0

我需要一些关于Swift中关闭引用的解释。 这里是我使用的情况下,让我们想象,我们有:关闭中强,弱和无主自我解释

class A {...} 
class B { 

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

是否有A类和B或不之间的挡周期? 在这种情况下,它可能是一个保留周期?

回答

2

因为不知道completion是否为@escaping(例如,如果它被保留),所以不可能说出A.someFunctionA。对于其余的答案,我将假定它是@escaping

Swift需要确保运行时安全,并将保留未来可能需要的任何对象,在这种情况下,通过强烈参考self(因为self是封闭内部使用的唯一变量)。

在这种情况下没有参考周期。这是因为instanceA不被保留,所以A => B,但乙!=> A.

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

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

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

如果不确定,请使用weak

+0

谢谢你的回答!只是为了确认,所以当我在类B的函数内部创建一个instanceA:A时,它仅在函数的上下文中考虑,而不是该类的引用?做出强有力的参考的唯一方法是让instanceA:A类的属性?还有一个问题,如果我不把@escaping,封闭不保留自我? – Arrabidas92

+1

是的,在这种情况下'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

+1

这是错误的。在这种情况下,您不会有保留周期,因为常量instanceA在函数内部创建。 – Alex

+0

谢谢你的回答!只是为了确认,所以当我在类B的函数内部创建一个instanceA:A时,它仅在函数的上下文中考虑,而不是该类的引用?做出强有力的参考的唯一方法是让instanceA:A类的属性? – Arrabidas92

+1

@Alex哎呀!我将编辑答案以删除该部分。 其余的部分仍然有效,所以我会把它留在那里。 – royalmurder