1

我经常看到的关于强引用循环的例子涉及两个属性相互指向的类。但是,如果只有一个类具有指向另一个实例的属性,如下所示:

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吗?

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

4

1 回答 1

2

正如@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

需要注意的是,即使您设置myClassBnilfirst,它也会首先myClassA被释放。当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。您选择哪一个会影响对象被释放的顺序:

如果您weak var classB: ClassB声明ClassA

输出:

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
于 2016-05-22T12:43:51.850 回答