Short answer: The instance variable a->_refObject
is not (yet) nil in -[B dealloc]
,
but each access to that weak pointer is done through a ARC runtime function
that returns nil if the deallocation has already begun.
Long answer: By setting a watchpoint you can see that a->_refObject
is set to nil at the end of the
deallocation process. The stack backtrace (when the watchpoint is hit) looks like this:
frame #0: 0x00007fff8ab9f0f8 libobjc.A.dylib`arr_clear_deallocating + 83
frame #1: 0x00007fff8ab889ee libobjc.A.dylib`objc_clear_deallocating + 151
frame #2: 0x00007fff8ab88940 libobjc.A.dylib`objc_destructInstance + 121
frame #3: 0x00007fff8ab88fa0 libobjc.A.dylib`object_dispose + 22
frame #4: 0x0000000100000b27 weakdealloc`-[B dealloc](self=0x000000010010a640, _cmd=0x00007fff887f807b) + 151 at main.m:28
frame #5: 0x0000000100000bbc weakdealloc`-[A foo](self=0x0000000100108290, _cmd=0x0000000100000e6f) + 140 at main.m:41
frame #6: 0x0000000100000cf5 weakdealloc`main(argc=1, argv=0x00007fff5fbff968) + 117 at main.m:52
frame #7: 0x00007fff8c0987e1 libdyld.dylib`start + 1
and object_dispose()
is called from -[NSObject dealloc]
(as can be seen in
http://www.opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm).
Therefore in -[B dealloc]
, a->_refObject
is not nil before the (compiler generated) [super dealloc]
is called.
So the question remains: Why does a.refObject
return nil at that point?
The reason is that for each access to a weak pointer the ARC compiler generates
a call to objc_loadWeak()
or objc_loadWeakRetained()
. From the documentation:
id objc_loadWeakRetained(id *object)
If object is registered as a __weak object, and the last value stored into object has not > yet been deallocated or begun deallocation, retains that value and returns it. Otherwise > returns null.
So even if a->refObject
is not nil at that point, accessing the weak pointer
via objc_loadWeakRetained()
(as done by the property accessor method) returns nil,
because the deallocation of the B
object has already begun.
The debugger accesses a->refObject
directly and does not call objc_loadWeak()
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…