class A {
var b: B
init(b: B) {
self.b = b
}
deinit {
print(" Destroying A")
}
}
class B {
weak var a: A?
deinit {
print(" Destroying B")
}
}
func setup(_ a: inout A?, _ b: inout B?) {
b = B()
a = A(b: b!)
b?.a = a
}
var bravo: B?
var alpha: A?
setup(&alpha, &bravo)
bravo = nil
alpha = nil
// OUTPUT:
// " Destroying A"
// " Destroying B"
I've tried all permutations of setting alpha
and bravo
to nil, and yet I cannot get bravo
to deinit before alpha
. Based on my brief experiment in Swift Playgrounds, alpha
always gets deinit before bravo
. Can someone please explain why?
I know this has to do with ARC, but I thought if bravo = nil
, then isn't the value of alpha.b
also nil? If so, then wouldn't it be safe to deinit bravo
safely before alpha
?
I'd love to know what the retain counts are on each of these instances over time.
CodePudding user response:
Not sure I understood the question, but I see this as quite straight forward application of ARC rules. After the line
setup(&alpha, &bravo)
you have
- 2 strong references to the object
bravo
(thebravo
itself, and its referencealpha.b
) - 1 strong (
alpha
itself), and 1 weak (bravo.a
) reference to the objectalpha
Now you set bravo = nil
, removing 1 strong reference, but the other strong reference remains, so deinit
is not called, based on rule:
ARC will not deallocate an instance as long as at least one active reference to that instance still exists.
Next you set alpha = nil
. That's deleting its only strong reference, hence based on rule
A weak reference is a reference that doesn’t keep a strong hold on the instance it refers to, and so doesn’t stop ARC from disposing of the referenced instance.
A can be deallocated immediately. Also important to remember that
ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated
In other words, the order of operations is:
- String reference is deleted with
alpha = nil
- Since there are no other strong references, all weak references are set to
nil
deinit
is called
So now, that alpha
is deleted, no references of any kind are left for bravo
, and hence its deinit
can be called.