由于引用周期,swift内存泄漏

由于引用周期,swift内存泄漏,swift,memory-leaks,Swift,Memory Leaks,有人能帮我避免下面的内存泄漏吗 class Base { var refer: Referenced? init() { self.refer = Referenced() } deinit { print("deinit called") } } class Referenced { var native: Native init(){ native = Native.init(bas

有人能帮我避免下面的内存泄漏吗

class Base {
     var refer: Referenced?
    init() {
        self.refer = Referenced()
    }
    deinit {
        print("deinit called")
    }
}



class Referenced {
    var native: Native
    init(){
       native = Native.init(baseRef: Base())
    }


}
struct Native {
    var baseRef: Base
}
func testMe () {
    var base:Base? = Base()
    base?.refer = nil
    base = nil
}

testMe()
看起来这里有一个循环引用。基础->引用和引用->本机->基础


但我不确定如何打破这个循环

将其中一个参考更改为弱,如下所示:

class Base {
    weak var refer: Referenced?
    init() {
        self.refer = Referenced()
    }
    deinit {
        print("deinit called")
    }
}

希望这会有所帮助。

您需要将
标记为Base。请将
Native.baseRef
引用为
,以打破循环,即将
var
更改为
弱var

首先,在您传递的代码片段中,您遇到了如下无限循环依赖的问题:

weak var baseRef: Base?
基础->参考->本机->基础

Native
struct的实例没有引用此链开头的
Base
实例,它总是创建一个新实例,并且此行为是无限的。把你的代码复制到操场上,然后试着运行它。您将收到一个
“执行被中断”
错误。 因此,您的代码甚至无法运行。我认为,您试图实现的是让
原生
结构保存对第一个
实例的引用。下面是正确的解决方案,我们将引用从
Base
传递到
Referenced
Native
,以保存引用:

class Base {
    var refer: Referenced?
    init() {
        self.refer = Referenced(base: self)
    }
    deinit {
        print("deinit called")
    }
}

class Referenced {
    var native: Native
    init(base: Base){
        native = Native.init(baseRef: base)
    }
}

struct Native {
    var baseRef: Base
}
现在,由于
Native
引用的是
Base
父级,您将与原始问题中提到的内存泄漏作斗争。这一次,为了防止内存泄漏,您必须使
baseRef
var像这样弱:

weak var baseRef: Base?

这里有两个问题:

  • 正如其他人所指出的,一般来说,当两个或两个以上的引用类型相互引用时,需要使其中一个引用
    ,以打破强引用循环。看

  • 这里更严重的问题是有无限循环。
    Base
    init
    正在实例化一个新的
    Referenced
    实例,但是
    Referenced
    init
    正在创建另一个
    Base
    实例(它正在传递给
    本机
    实例)。然后,新的
    Base
    实例将创建另一个
    引用的
    实例,重复此过程,并将继续执行此操作,直到内存/堆栈耗尽为止

    在各种
    init
    方法中添加
    print
    语句,您将看到这个无限循环在起作用

  • 您应该重新审视这个模型,确定一个“所有权”图。父对象可以保留对子对象的强引用(如果合适,还可能实例化子对象),但子对象应该只保留对其父对象的
    引用(并且很可能不会实例化新的父对象)

    例如,您可以执行以下操作:

    class Parent {
        var child: Child?
    
        init() {
            self.child = Child(parent: self)
        }
    
        deinit {
            print("deinit called")
        }
    }
    
    class Child {
        weak var parent: Parent?
    
        init(parent: Parent) {
            self.parent = parent
        }
    }
    

    在这里,您实例化一个
    父对象
    对象,它恰好实例化了一个子对象。但请注意:

  • 父项
    将自身作为参数提供给
    子项

  • 子项
    仅维护对父项的
    引用;及

  • 子级
    显然不会实例化新的
    父级
    ,而只是使用提供给它的引用

  • 您也可以使用
    本机
    结构
    进行此项的格式副本,但想法是一样的:使用
    引用打破强引用循环,避免无限循环



    坦率地说,在这些情况下,抽象类型名称会使示例变得不必要的混乱。如果您通过一个实际的示例来阐明这些不同类型的实际代表,那么所有权模型无疑将变得更加不言自明。

    内存泄漏是次要问题。在
    Base
    Referenced
    类之间存在无限循环依赖关系。如果将
    reference
    a
    属性设置为弱
    属性,则
    self.reference=Referenced()
    将立即解除分配。你是对的,
    引用可以打破强引用循环,但这里的示例不起作用。