我想我知道Swift上没有保留周期,为什么它会导致内存泄漏。 但是我写了一个小例子来演示它,看来代码无论如何都已正确释放。
在此示例中,我有两个互相保留的对象(创建了保留周期),而第三个对象强烈地同时保留了这两个对象。
我希望这第三个对象也无法释放,但不是。
互相保留的两个对象:
class Obj1: NSObject {
var objc2: Obj2?
deinit {
print("Obj1 Deinit")
}
}
class Obj2: NSObject {
var obj1: Obj1?
deinit {
print("Obj2 Deinit")
}
}
容器:
class Container {
var obj1: Obj1?
var obj2: Obj2?
deinit {
print("Container Deinit")
}
}
生成保留周期的代码
let obj1 = Obj1()
let obj2 = Obj2()
obj1.objc2 = obj2
obj2.obj1 = obj1
let c = Container()
c.obj1 = obj1
c.obj2 = obj2
控制台上的结果是:
Container Deinit
有人可以指出Container
为何被释放,即使其属性没有?
答案 0 :(得分:5)
有人可以指出
Container
为何被释放,即使其属性没有?
与该容器的属性仍然具有其他所有者无关。唯一重要的是容器中存在多少个强引用。
在您的示例中,只有一个强引用容器,即常量c
:
let c = Container()
当c
超出范围时(在程序/操场的末尾),容器对象被释放,并且由于没有其他强引用,因此将其释放。
(在旁边:容器的释放继而导致容器释放对其属性obj1
和obj2
的强引用。但是由于仍然存在对这些对象的其他强引用,因此它们不存在正如您正确指出的那样,将其释放。)
答案 1 :(得分:4)
除了您的let c = Container()
常量以外,没有其他对象可以容纳容器。
对象的属性不包含对其“父”对象的引用(除非您保留对其的显式非弱和非私有引用)。
由于swift使用ARC(automatic reference counting),因此手动保持引用计数以查看发生的情况可能会有所帮助:
let obj1 = Obj1() // Obj1 has 1 reference (this let)
let obj2 = Obj2() // Obj2 has 1 reference (this let)
obj1.objc2 = obj2 // Obj2 has 2 references (property in obj1)
obj2.obj1 = obj1 // Obj1 has 2 references (property in obj2)
let c = Container() // Container has 1 reference
c.obj1 = obj1 // Obj1 has 3 references (property in container)
c.obj2 = obj2 // Obj2 has 3 references (property in container)
// c is deallocated -- Container has 0 references and deinit is called
// as a consequence, now both Obj1 and Obj2 have 2 references only
// the "let obj1" is deallocated -- Obj1 has still 1 reference from Obj2
// the "let obj2" is deallocated -- Obj2 has still 1 reference from Obj1
请注意,如果您更改解除分配的顺序(第一个obj1和obj2以及之后的c),则最终结果不会改变。
希望能说明这一点。 :)
答案 2 :(得分:-1)
您在容器内部持有“ Obj1”和“ Obj2”的引用,但未在“ Obj1”或“ Obj2”内部持有该容器的引用