这个Swift代码应该会产生内存泄漏,但不会。有人可以指出原因吗?

时间:2018-06-21 09:40:46

标签: swift retain-cycle retaincount

我想我知道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为何被释放,即使其属性没有?

3 个答案:

答案 0 :(得分:5)

  

有人可以指出Container为何被释放,即使其属性没有?

与该容器的属性仍然具有其他所有者无关。唯一重要的是容器中存在多少个强引用。

在您的示例中,只有一个强引用容器,即常量c

let c = Container()

c超出范围时(在程序/操场的末尾),容器对象被释放,并且由于没有其他强引用,因此将其释放。

(在旁边:容器的释放继而导致容器释放对其属性obj1obj2的强引用。但是由于仍然存在对这些对象的其他强引用,因此它们不存在正如您正确指出的那样,将其释放。)

答案 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”内部持有该容器的引用