LoginSignup
14
14

More than 5 years have passed since last update.

weak を unsafe_unretained に書き換える際の注意点

Last updated at Posted at 2013-02-07

ARC-enabled なライブラリを Snow Leopard に対応させるために、 weak 修飾子を unsafe_unretained 修飾子に書き換たいことがまれにある。基本的には単純に書き換えるだけでいいが、注意すべき点が2つある:

  1. unsafe_unretained プロパティが参照するオブジェクトが解放されたらプロパティに nil をセットする
  2. __unsafe_unretained 変数が参照するオブジェクトを使う前に強参照を作る

1. プロパティについて

weak プロパティはオブジェクトが解放されると同時に nil がセットされるが、 unsafe_unretained プロパティは無効な領域を参照し続ける:

@property(weak) id weakProp;
@property(unsafe_unretained) id unsafeUnretainedProp;

// ...

- (void)propExample {
    id obj = [[NSObject alloc] init];

    self.weakProp = obj;
    self.unsafeUnretainedProp = obj;

    obj = nil; // ここでオブジェクトが解放される

    // ここでは self.weakProp == nil
    // ここでは self.unsafeUnretainedProp == 無効なアドレス
}

weak プロパティを unsafe_unretained プロパティに書き換えた場合、参照しているオブジェクトが解放されたタイミングで nil をセットしてやる必要がある。

上に掲載した例は同一スコープ内でオブジェクトを作ってすぐ解放する単純なコードなので解放タイミングが掴みやすいが、実際の参照関係はより複雑になる場合がほとんどである:

- (void)complexRefExample {
    self.unsafeUnretainedProp = [self.mutableDict objectForKey:@"obj"];

    [self.mutableDict removeObjectForKey:@"obj"];

    // ここで、
    // 強参照していたのが self.mutableDict だけなら:
    //     self.unsafeUnretainedProp == 無効なアドレス
    // 他のオブジェクトがまだ強参照しているなら:
    //     self.unsafeUnretainedProp == オブジェクトの有効なアドレス
}

オブジェクトが解放されるタイミングが予測できない場合、メモリリークする可能性と引き換えに strong プロパティを使う手もある。

2. 変数について

__weak 変数も weak プロパティと同様に、参照するオブジェクトが解放されると同時に nil がセットされる:

- (void)varExample1 {

    id obj = [[NSObject alloc] init];

    __weak id weakVar = obj;
    __unsafe_unretained id unsafeUnretainedVar = obj;

    obj = nil; // ここでオブジェクトが解放される

    // ここでは weakVar == nil
    // ここでは unsafeUnretainedVar == 無効なアドレス
}

__weak 変数を __unsafe_unretained 変数に書き換えた場合、手動で nil をセットする代わりに、強参照を作ってオブジェクトを解放させないようにするのが手軽である:

- (void)varExample2 {
    {
        id obj = [[NSObject alloc] init];

        __unsafe_unretained id unsafeUnretainedVar = obj;
        id var = unsafeUnretainedVar;

        obj = nil; // まだ var が参照しているのでオブジェクトは解放されない

        // ここでは unsafeUnretainedVar == obj
    }
}
14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14