我正在寻找将函数作为变量存储在其他对象中的最佳实践。具体而言,我希望避免在函数中捕获self
时产生的保留循环。
来自Objective-C和Blocks的经验告诉我通常会这样做:
__weak id _self = self;
iVar.someBlock = ^{
[_self doSomething];
};
当然,iVar
类会复制并存储该块。 我使用__weak id _self
捕获,因此不存在保留周期。
在Swift中,我不太确定,特别是因为我可以传递类函数/方法。假设在iVar
类中,我有:
class iVarClass {
var callBack:() -> ()?
func jumpUpAndDown(){
//Weeeeeee!
self.callBack?()
}
}
现在在我的“主”类中,我有一个上述类的实例变量,并且我执行以下操作:
class mainClass {
var iVar: iVarClass
init(iVar:iVarClass){
self.iVar = iVar
iVar.callback = self.doSomething
}
func doSomething(){
self.iVar.jumpUpAndDown?()
}
}
这里是否存在一个保留循环?我认为是的,并且也许我需要使 callback
变为弱引用:
weak var callBack:() -> ()?
当然,我可以在主类中这样做:
init(iVar:iVarClass){
self.iVar = iVar
weak var _self = self
iVar.callback = {
_self?.doSomething()
}
}
但是将类函数作为参数传递的能力真的很好!另外,如果我确实需要使callback
弱引用,那么我认为我将失去分配闭包的能力(因为在分配后,闭包将仅具有一个弱引用并从内存中释放)。
此外,请注意,现在内存管理责任落在接收者而不是分配者身上,但由于接收者无法知道分配的来源,因此无法真正承担责任。换句话说,现在接收者和分配者之间必须有一个隐含的合同,规定应该传递何种类型的函数,这是脆弱且不推荐的。当分配者负责时,它可以采取措施确保没有保留周期,但接收者不能采取这样的步骤。
这让我想到我们永远不应该将类函数传递给另一个对象。这太危险了。你无法知道接收者将如何存储/使用它。
或者我错过了什么?Swift是否在幕后神奇地解决了这个问题?
更新
@Kirsteins指出我忘记了一些内容:捕获列表。因此,您可以在闭包中声明它,而不是显式声明weak var _self = self
:
init(iVar:iVarClass){
self.iVar = iVar
iVar.callback = { [weak self] in
self?.doSomething()
}
}
这样做比之前的方式更好,但是并不像直接分配类函数那样优雅。
我认为我想要Swift自动将类函数转换为带有捕获列表的闭包,这样我就不必自己做了。说实话,这并不算难,但如果我可以直接分配类函数,那肯定更美观。甚至,即使像这样也会更好:
self.iVar.callback = weak self.doSomething