由于引用周期,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()
将立即解除分配。你是对的,弱
引用可以打破强引用循环,但这里的示例不起作用。