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

kanetaiの二次記憶装置

プログラミングに関するやってみた、調べた系のものをQitaに移して、それ以外をはてブでやる運用にしようと思います。http://qiita.com/kanetai

Objective-Cの所有修飾子(ownership qualifier)

ARCを使用しない場合の参照カウンタ方式の処理

alloc クラスからインスタンスを生成, retainCount←1
retain retainCount++
release retainCount--

ARCが有向の場合、コンパイラがretainやreleaseを自動挿入してくれるので、retainやreleaseの記述は不要(というか記述があるとエラーになるはず)。

ARCが有効な場合

ARCが有効な場合には、オブジェクト型の変数に所有修飾子(ownership qualifier)をつける。

__strong

強い参照(strong reference)。所有修飾子を省略すると__strongになる。
代入すると、retainCount++され、ブロックを抜けるとretainCount--される。

hoge *a;
{
    hoge *b  = [hoge alloc] init]; //retainCount = 1;
    a = b;                         //retainCount++;
}                                  //retainCount--;
NSLog(@"%@", a);
__unsafe_unretained

retainメッセージが送られない。循環参照(retain cycle)になっている(相互に強い参照で結びついている)場合、オブジェクトが解放できなくなるのを防ぐために使用する。

//retain cycle
instanceA.vara = instanceB;
instanceB.varb = instanceA;
hoge __unsafe_unretained *a;
{
    hoge *b = [hoge alloc] init]; //retainCount = 1;
    a = b;                        //retainCount変化なし
}                                 //retainCount--;
NSLog(@"%@", a);  //retainCountが0になって解放されるまでに多少時差があるため、クラッシュしない可能性もある。
NSLog(@"%@", a);  //解放されていたらクラッシュ
__weak

弱い参照(weak reference)。基本的に__unsafe_unretainedと同じだが、元のインスタンスが破棄されると、nilが代入される(ゼロ化(Zeroing))。nilに対して、メッセージを送ってもクラッシュはしない。
※Mac OSX 10.6とiOS 4では使用できないため、ARCを有効にして、古いOSでも動作させるためには、__unsafe_unretainedを使う必要がある。

hoge __weak *a;
{
    hoge *b = [hoge alloc] init]; //retainCount = 1;
    a = b;                        //retainCount変化なし
}                                 //retainCount--;
NSLog(@"%@", a);  //破棄されていたらnil
__autoreleasing

@autoreleasepoolブロックの開始時に生成される自動解法プール(登録したインスタンスをまとめて解放する領域)に登録する。コンビニエンスコンストラクタを使用してインスタンスを生成した場合には、自動的に自動解法プールに登録されるため、__autoreleasingを使う機会は多くない。

hoge __weak *a;
@autoreleasepool {
    {
        hoge __autoreleasing *b = [[hoge alloc] init]; //retainCount = 1;
        a = b;                                         //retainCount変化なし
    }                                                  //retainCount変化なし
    NSLog(@"%@", a); //no problem
}                                                      //retainCount--;
NSLog(@"%@", a); //破棄されていたらnil

ARC未使用-->ARC使用に変換するには、
Xcodeの[File]->[Refactor]->[Convert to Objective- ARC]->ターゲットにチェック->[Prencheck]->[Next]->[Save]
保存前にdiffがでるのでそれを見て確認できる。また、変更前のスナップショットを保存するか尋ねられる。保存する場合は[Enable]。