2013-04-20 4 views
10

ではありません私は有効ARCでのObjective-Cで次のように気づい:のは、単純なクラスAを持ってみましょう弱い性質がのdeallocにnilに設定されますが、プロパティのIVARがnil

をして

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

@implementation A 
@end 

弱い性質をautosynthesizedと

:deallocを持つ2番目のクラスBは

@interface B 
@end 

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

そして最後にどこかのクラスAで次を実施しています

@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 

私は[B dealloc]にブレークポイントを設定し、[A refObject]プロパティを検査した場合、私はa.refObjectがnilであるが、a->_refObjectが「B」にゼロとポイントではないことがわかります

それがなぜ起こるか任意のアイデア?

+0

弱い参照をクリアすべきであることが分かっているにもかかわらず、アクセッサメソッドは 'nil'を返すかもしれませんが、インスタンス変数自体はそのまま残されています(割り当てが解除され、今はダングリングポインタです)。 –

+0

私はdeallocではオブジェクトはまだ有効で、まだ削除されていないと思います。たとえばNSNotificationCenterから登録を解除し、そのプロパティにアクセスできます。 –

+0

「アクセスできます」とは必ずしも割り当て解除されていないわけではありませんが、間違っている可能性があります。 –

答えて

22

短い答え:インスタンス変数a->_refObjectありません(まだ)はnilで-[B dealloc]、 が、その弱いポインタへの各アクセスは解除がすでに始まっている場合はnilを返しARCランタイム機能 を介して行われます。

長い答え:あなたがa->_refObjectが 解除プロセスの最後にnilに設定されていることを確認できウォッチポイントを設定することにより。スタックバックトレース(ウォッチポイントがヒットした)次のようになります。

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 

object_dispose()http://www.opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mmに見られるように)-[NSObject dealloc]から呼び出されます。

したがって、-[B dealloc]では、a->_refObjectは、(コンパイラが生成した)[super dealloc]が呼び出される前はnilではありません。

したがって、質問が残っています。なぜ、a.refObjectはその時点でnilを返しますか?

弱いポインタへのアクセスごとに、ARCコンパイラが を呼び出してobjc_loadWeak()またはobjc_loadWeakRetained()を呼び出したためです。 documentationから:

ID objc_loadWeakRetained(識別*オブジェクト)

オブジェクトが__weakオブジェクトとして登録され、オブジェクトに格納された最後の値がまだ割り当て解除または解放を開始し、保持されていない>た場合その値を返します。それ以外の場合はnullを返します。

Bオブジェクトの解放が既に始まっているので、それでa->refObjectは(プロパティのアクセッサメソッドによって行われる)objc_loadWeakRetained()介し弱いポインタ にアクセスし、その時点でゼロではない場合であってもゼロ、 を返します。

デバッガはa->refObjectに直接アクセスし、objc_loadWeak()を呼び出しません。

+0

Noceありがとう。私は弱いポインタがアクセスされるたびにコンパイラがobjc_loadWeakを追加すると思ったが、 - > _ refObjのケースではないようだ。 –

+0

@plamkata__:*コンパイラは、 'a-> refObject'へのアクセスごとに' objc_loadWeak [ *デバッガのみが直接ivarにアクセスします。 –

+0

理にかなう。私は、その動作を観察したとき、deallocメソッドでNSLogを使用してivarをダンプすると、それが私を混乱させたという印象を受けました。しかし、実際に私はNSLogを使わずにデバッガを使っていました。助けてくれてありがとう。 –