有人可以帮我避免下面的内存泄漏
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()
好像这里有一个循环引用。基本->引用和引用->本机->基本
但是我不确定如何打破这个循环。
答案 0 :(得分:2)
这里有两个问题:
正如其他人指出的那样,通常,当您有两个或多个相互引用的引用类型时,您需要创建其中一个引用weak
才能打破强大的引用周期。参见Resolving Strong Reference Cycles Between Class Instances。
这里最严重的问题是您有无限循环。 init
的{{1}}实例化了一个新的Base
实例,但是Referenced
的{{1}}正在创建另一个init
实例(该实例将传递给Referenced
实例)。然后,该新的Base
实例将创建另一个Native
实例,重复该过程,并将继续执行该过程,直到耗尽内存/堆栈。
在各种Base
方法内添加Referenced
语句,您将看到此无限循环的实际作用。
您应该重新访问该模型,标识一个“所有权”图。父对象可以保留对子对象的强引用(如果合适,还可以实例化子对象),但是子对象只能将print
引用保留回其父对象(并且很可能不实例化新的父对象)。>
例如,您可以这样做:
init
和
weak
在这里,您实例化了一个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
}
}
对象,该对象恰巧实例化了一个孩子。但请注意:
func testMe() {
var parent: Parent? = Parent()
parent = nil // in this case, this is unnecessary because `parent` is a local variable, but this is here for illustrative purposes; but note that we don’t have to `nil` the `child`
}
将自身作为参数提供给Parent
;
Parent
仅保留对Child
的{{1}}引用;和
Child
显然不会实例化新的weak
,而只是使用提供给它的引用。
您也可以使用Parent
Child
对此进行演绎,但是想法是一样的:用Parent
引用打破强引用周期并避免无限循环。
坦率地说,在这些情况下,抽象类型名称使示例不必要地引起混淆。如果通过一个实际的,真实的示例来阐明这些类型的实际含义,所有权模型无疑将变得更加不言而喻。
答案 1 :(得分:0)
将其中一个引用更改为弱:
class Base {
weak var refer: Referenced?
init() {
self.refer = Referenced()
}
deinit {
print("deinit called")
}
}
希望这会有所帮助。
答案 2 :(得分:0)
您需要将Base.refer
或Native.baseRef
标记为weak
才能中断循环,即将var
更改为weak var
。
答案 3 :(得分:0)
首先,在您传递的代码段中,存在无限循环依赖的问题,如下所示:
基本->引用->本机->基本...
在该链的开头,Native
结构的实例未引用Base
实例,它始终在创建一个新实例,并且这种行为是无限的。只需将代码复制到操场上并尝试运行它。您将收到一个"Execution was interrupted"
错误。
因此,您的代码甚至无法运行。正如我想的那样,您要实现的目标是让Native
结构保留对第一个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?