这是强引用循环还是内存泄漏?

Is this a strong reference cycle or memory leak at all?

我经常看到的关于强引用循环的例子涉及两个类,它们的属性相互指向。但是,如果只有一个 类 有一个 属性 指向另一个实例,就像这样:

class ClassA {
    var classB: ClassB? = nil
}

class ClassB {

}

然后我这样创建我的实例:

var myClassA = ClassA()
var myClassB = ClassB() //Reference count 1
myClassA.classB = myClassB //Reference count 2

// Now deallocate
myClassB = nil  //Reference count 1
myClassA = nil

自从我释放 myClassB 后,引用计数为 1。myClassA.classB 的引用计数发生了什么变化?它从未达到零,因为我从未做过 myClassA.classB = nil 或使用 deinit 来做到这一点。自从我 myClassA = nil?

之后,这是隐式完成的吗?

这可以归类为强引用循环吗?我想这至少是内存泄漏,这是真的吗?

正如@ozgur、@jtbandes、@Avi 和@Rob 在评论中解释的那样,没有强引用循环或泄漏。

这是一个基于@Rob 的评论的示例,您可以在 Playground 中 运行:

class ClassA {
    var classB: ClassB?

    deinit {
        print("ClassA deallocated")
    }
}

class ClassB {
    deinit {
        print("ClassB deallocated")
    }
}

class Tester {
    func test() {
        var myClassA: ClassA! = ClassA()
        var myClassB: ClassB! = ClassB() //Reference count 1
        myClassA.classB = myClassB //Reference count 2

        // Now deallocate
        print("setting myClassB to nil")
        myClassB = nil  //Reference count 1
        print("setting myClassA to nil")
        myClassA = nil
        print("all done")
    }
}

// Create `Tester` object and call `test`:

Tester().test()

输出:

setting myClassB to nil
setting myClassA to nil
ClassA deallocated
ClassB deallocated
all done

需要注意的是,即使您先将 myClassB 设置为 nilmyClassA 也会先被释放。当 myClassA 被释放时,对 myClassB 的最终引用被 ARC 释放,然后 myClassB 被释放。


为了展示强引用循环,让 ClassB 保留对 ClassA 的强引用:

class ClassA {
    var classB: ClassB?

    deinit {
        print("ClassA deallocated")
    }
}

class ClassB {
    var classA: ClassA?

    deinit {
        print("ClassB deallocated")
    }
}

class Tester {
    func test() {
        var myClassA:ClassA! = ClassA()
        var myClassB:ClassB! = ClassB() //Reference count 1
        myClassA.classB = myClassB //Reference count 2
        myClassB.classA = myClassA

        // Now deallocate
        print("setting myClassB to nil")
        myClassB = nil  //Reference count 1
        print("setting myClassA to nil")
        myClassA = nil
        print("all done")
    }
}

Tester().test()

输出:

setting myClassB to nil
setting myClassA to nil
all done

如果两个对象都包含对另一个的强引用,则两个对象都不会被释放。要打破这种强引用循环,请将 classBclassA 属性之一声明为 weak。您选择哪一个会影响对象被释放的顺序:

如果您在 ClassA 中声明 weak var classB: ClassB

输出:

setting myClassB to nil
ClassB deallocated
setting myClassA to nil
ClassA deallocated
all done

如果相反,您声明 weak var classA: ClassA in ClassB:

输出:

setting myClassB to nil
setting myClassA to nil
ClassA deallocated
ClassB deallocated
all done