読者です 読者をやめる 読者になる 読者になる

__unsafe_unretainedと__weak

久しぶりに仕事で、__unsafe_unretained修飾子が使われているのを見つけて「あれ、これ__weakとどう違うんだっけ?」と疑問に思い、調べ直したのでメモっておく。

Effective Objective-C 2.0

Effective Objective-C 2.0

Q : そもそも__unsafe_unretainedと__weak修飾子は何か?
A : 両方とも循環参照が起こらないように導入されたプロパティの管理属性(ランタイム修飾子)である。

weak

新しい値がセットされた場合にretainされず、元々の値はreleaseされない。
プロパティが示すオブジェクトが破棄されたときnilに置き換えられる。

__unsafe_unretained

意味合いとしてはassignと同じ。assignの扱うターゲットはスカラー型だけど、
__unsafe_unretainedの場合は、オブジェクト。
そして、プロパティが示すオブジェクトが破棄されてもnilにはならない

循環参照回避のためにiOS4までは__unsafe_unretainedが使われていたが、iOS5からweakが導入される。
基本的に弱い参照としてプロパティを指定する場合はweakを使うのが安全。
何故ならば、オブジェクトが破棄されてnilになったとして、nilにたいしてメッセージーを送っても
落ちないから。(何も起きない)

実際に、コードで挙動を確認すると・・・


これはクラッシュしないけど

-(void) mogeWeakTest {
    
    __weak Moge *aMoge = nil;
    
    @autoreleasepool {
        Moge *bMoge = [[Mogealloc] init];
        aMoge = bMoge;
        NSLog(@"bMoge %@",bMoge);
        NSLog(@"aMoge %@",aMoge);
    }
    
  
    NSLog(@"aMoge %@",aMoge);
    [aMoge action]; // メモリが解放されていたらaMogeはnilになる
    
}

こっちはクラッシュする場合がある。
(aMogeが破棄されていた場合)

-(void) mogeUnsafedTest {
    
    __unsafe_unretained Moge *aMoge = nil;
    
    @autoreleasepool {
        Moge *bMoge = [[Mogealloc] init];
        aMoge = bMoge;
        NSLog(@"bMoge %@",bMoge);
        NSLog(@"aMoge %@",aMoge);
    }
   
    NSLog(@"aMoge %@",aMoge);
    [aMoge action]; // aMogeが解放されていた場合はクラッシュ
    
}

基本的に弱い参照は_weak修飾子が安全ですね。