Swift 内存管理:在 var 中存储 func

Posted

技术标签:

【中文标题】Swift 内存管理:在 var 中存储 func【英文标题】:Swift Memory Management: Storing func in var 【发布时间】:2015-03-22 14:54:01 【问题描述】:

我正在寻找将函数作为变量存储在其他对象中的最佳实践。具体来说,我希望避免在函数中捕获 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 变弱,那么我想我会失去为它分配闭包的能力(因为在分配之后,闭包将从内存中释放,只有一个弱引用)。

另外,请注意,内存管理责任现在由接收者而不是分配者承担,但由于接收者无法知道分配的来源,因此它不能真正负责。换句话说,现在接收者和分配者之间必须有一个关于传递什么样的函数的隐式契约,这是脆弱的,不推荐。当assigner负责时,它可以采取措施确保没有retain cycle,但receiver不能采取这种措施。

这让我觉得我们应该永远将一个类函数传递给另一个对象。这太危险了。您无法知道接收器将如何存储/使用它。

或者我错过了什么? 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

【问题讨论】:

你能找到更多关于这个主题的信息吗?我觉得奇怪的是这个看似很常见的用例没有对应的语法 不,我什么都没看到。似乎捕获列表是Apple的答案。不过,这似乎是一个错失的机会,因为更简单的系统会使对象更加可组合。 【参考方案1】:

你不能这样做吗:

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

据我了解,这样您就不会直接捕获self,从而避免了保留周期。

【讨论】:

以上是关于Swift 内存管理:在 var 中存储 func的主要内容,如果未能解决你的问题,请参考以下文章

AppDelegate 类型 var 不是成员,除非在 func 中(见图)

Swift 实践:属性

Swift 值类型和引用类型的内存管理

Swift app声音管理库 Chirp

Swift 栈和堆

swift 4.2 - 如果var具有有效的枚举值,我如何检查guard