As @ozgur, @jtbandes, @Avi, and @Rob explained in the comments, there is no strong reference cycle or leak.
Here is an example based upon @Rob's comment that you can run in a 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()
Output:
setting myClassB to nil
setting myClassA to nil
ClassA deallocated
ClassB deallocated
all done
The thing to note is that even though you set myClassB
to nil
first, that myClassA
gets freed first. When myClassA
gets freed, the final reference to myClassB
is released by ARC and then myClassB
is freed.
To demonstrate a strong reference cycle, have ClassB
retain a strong reference to 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()
Output:
setting myClassB to nil
setting myClassA to nil
all done
Neither object is deallocated if they both contain strong reference to the other. To break this strong reference cycle, declare one of the classB
or classA
properties to be weak
. Which one you choose affects the order that the objects get freed:
If you declare weak var classB: ClassB
in ClassA
:
Output:
setting myClassB to nil
ClassB deallocated
setting myClassA to nil
ClassA deallocated
all done
If instead, you declare weak var classA: ClassA in ClassB
:
Output:
setting myClassB to nil
setting myClassA to nil
ClassA deallocated
ClassB deallocated
all done