Swift内存管理:将函数存储在变量中

7

我正在寻找将函数作为变量存储在其他对象中的最佳实践。具体而言,我希望避免在函数中捕获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

你能否在这个主题上找到更多的信息?我觉得很奇怪,这种看似非常普遍的用例没有相应的语法。 - Allen Zeng
没有,我什么都没看到。似乎捕获列表是苹果的答案。不过这似乎是一个错失的机会,因为更简单的系统会使对象更加可组合。 - Aaron Hayman
1个回答

0

你不能做这样的事吗:

class mainClass {
    var iVar: iVarClass
    init(iVar:iVarClass){
        self.iVar = iVar
        func go() {
            self.doSomething()
        }
        iVar.callback = go
    }
    func doSomething(){
      self.iVar.jumpUpAndDown?()
    }
}

据我理解,这种方式可以避免直接捕获self,从而避免保留循环。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接