2013-04-20 2 views
10

Ich bemerkte die folgend in Objective-C mit ARC aktiviert:Schwache Eigenschaft auf null in dealloc aber Ivar Eigentum ist nicht gleich Null

die einfache Klasse A haben lassen und autosynthesized schwache Eigenschaft

@interface A 
@property (nonatomic, weak) id refObject; 
@end 

@implementation A 
@end 

Und zweite Klasse B mit dealloc implementiert

@interface B 
@end 

@implementation B 
-(void) dealloc 
{ 
    NSLog(@"In dealloc"); 
} 
@end 

Und schließlich irgendwo in der Klasse A haben die folgende:

@implementation A 
... 
-(void) foo 
{ 
    B* b = [B new]; 
    self.refObject = b; 
    // Just use b after the weak assignment 
    // in order to not dealloc 'b' before assignement 
    NSLog(@"%@", b); 
} 
... 
@end 

Wenn ich einen Haltepunkt in [B dealloc] gesetzt und [A refObject] Eigentum inspizieren kann ich sehen, dass a.refObject Null ist aber a->_refObject ist nicht gleich Null und zeigt auf ‚b‘

Irgendwelche Ideen, warum das passiert?

+0

Vielleicht gibt die Accessor-Methode 'nil' zurück, wenn sie weiß, dass das schwache ref gelöscht werden sollte, aber die Instanzvariable selbst wird intakt gelassen (und freigegeben, und jetzt ist sie ein fliegender Zeiger). –

+0

Ich denke, dass in Dealloc das Objekt noch gültig ist und noch nicht gelöscht. Sie heben die Registrierung zum Beispiel von NSNotificationCenter auf und können auf seine Eigenschaften zugreifen. –

+0

"Sie können darauf zugreifen" bedeutet nicht unbedingt, dass es nicht freigegeben ist, aber ich kann mich irren. –

Antwort

22

Kurze Antwort: Die Instanzvariablen a->_refObject ist (noch) nicht gleich Null in -[B dealloc], aber jeder Zugriff auf diesen schwachen Zeiger wird durch eine ARC Laufzeitfunktion getan, die Null zurück, wenn die Aufhebung der Zuordnung hat bereits begonnen.

Lange Antwort: Durch einen Beobachtungspunkt Einstellung können Sie sehen, dass a->_refObject auf Null am Ende des Deallokation Prozess eingestellt wird. Der Stapel Backtrace (wenn der Beobachtungspunkt getroffen wird) sieht wie folgt aus:

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 

und object_dispose() von -[NSObject dealloc] genannt wird (wie in http://www.opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm zu sehen).

Daher in -[B dealloc], a->_refObject ist nicht Null vor dem (Compiler generiert) [super dealloc] heißt.

So bleibt die Frage: Warum gibt a.refObject an diesem Punkt Null zurück?

Der Grund ist, dass der ARC-Compiler für jeden Zugriff auf einen schwachen Zeiger einen Aufruf an objc_loadWeak() oder objc_loadWeakRetained() generiert. Von dem documentation:

id objc_loadWeakRetained (id * Objekt)

Wenn Objekt als __weak Objekt registriert ist, und der letzte Wert in Objekt gespeichert hat, nicht> noch freigegeben oder Aufhebung der Zuordnung begonnen wurde, behält dieser Wert und gibt es zurück. Andernfalls> gibt null zurück.

Also selbst wenn a->refObject ist an diesem Punkt nicht gleich Null, den schwachen Zeigers über objc_loadWeakRetained() Zugriff auf nil (wie von der Eigenschaft Accessor-Methode durchgeführt), , weil die Aufhebung der Zuordnung des B Objekts bereits begonnen hat.

Der Debugger greift direkt auf a->refObject zu und ruft objc_loadWeak() nicht auf.

+0

Noce danke. Ich dachte, dass jedes Mal, wenn der schwache Zeiger zugegriffen wird, der Compiler objc_loadWeak hinzufügt, aber das scheint nicht der Fall zu sein mit einem -> _ refObj –

+0

@plamkata__: Der * Compiler * fügt 'objc_loadWeak [beibehalten]' für jeden Zugriff auf 'a-> refObject' hinzu , nur der * Debugger * greift direkt auf den Ivar zu. –

+0

Macht vollkommen Sinn. Ich hatte den Eindruck, dass, als ich dieses Verhalten beobachtete, ich NSLog in der Dealloc-Methode benutzte, um den Ivar zu entleeren, und das verwirrte mich. Aber eigentlich habe ich NSLog nicht benutzt, sondern Debugger, so wie Sie es direkt angesprochen haben. Danke nochmal für die Hilfe. –

Verwandte Themen