Objective-C ではガーベージコレクション機能が用意されていますが、iPhone アプリ開発などではメモリ管理をガーベージコレクションに任せずに自分で管理する必要があったりします。
メモリ管理のルールとして、自分でメモリを割り当てたものは自分で開放する、自分で retain をしたものは 自分で release するなど、いくつかルールがあるのでそのメモです。
retain と release についてのメモ
init〜 で始まるメソッドで確保したオブジェクトは release する必要がある
Objective-C のオブジェクト初期化メソッドのルールに、init〜 で始まるメソッドで確保したオブジェクトは自身で解放する必要がある、というものがあります。
例えば次の例のような場合は、自分で責任をもって release する必要があります。
NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:@"hoge", @"foo", nil]; [array release];
init〜 で始まらないメソッドで確保したオブジェクトは自身で解放してはいけません。
NSMutableArray *array = [NSMutableArray arrayWithObjects:@"hoge", @"foo", nil];
メソッド内でのみ使用するローカル変数を init〜 で確保した場合は autorelease をつける
テクニックの一つとして、メソッド内でのみ使用するローカル変数を init〜 メソッドで初期化した場合は autorelease を付けて release し忘れを防ぐようにします。
Google Objective-Cスタイルガイド 日本語訳
参考: Google Objective-Cスタイルガイド 日本語訳
- (void)doSomething { NSArray *array = [[[NSArray alloc] initWithObjects:@"hoge", @"foo", nil] autorelease]; // なにかの処理 }
メンバ変数を使用してオブジェクトを保持する場合のルール
次のいずれかの方法でメンバ変数でオブジェクトを保持する場合は dealloc メソッドで release を行う必要があります。
- メンバ変数に init〜 で始まるメソッドで初期化したオブジェクトを割り当てている場合
- メンバ変数に明示的に retain して保持することを示したオブジェクトを割り当てた場合
- プロパティに retain 属性または copy 属性が付いていて、プロパティでオブジェクトを割り当てた場合
MyClass.h
@interface MyClass : NSObject { @private NSMutableArray *array_; NSString *message_; } @property(retain) NSMutableArray *array; @property(copy) NSString *message; @end
MyClass.m
#import "MyClass.h" @implementation MyClass @synthesize array = array_; @synthesize message = message_; - (id)init { if ( (self = [super init]) ) { // 1) メンバ変数に init〜 で設定したオブジェクトを割り当てる場合は dealloc で release する array_ = [[NSMutableArray alloc] initWithObjects:@"hoge", @"foo", nil]; // 2) メンバ変数に明示的に retain してオブジェクトを保持することをマークした場合は dealloc で release する message_ = [[array_ objectAtIndex:0] retain]; // 3.1) メンバ変数にプロパティでオブジェクトを割り当てた場合は dealloc で release する self.array = [NSMutableArray arrayWithObjects:@"hoge", @"foo", nil]; // 3.2) init〜 で始まるメソッドでオブジェクトを割り当てる場合はプロパティ形式で直接受け取ってはいけない。二重の参照カウントになってしまう。 // init〜 で確保したオブジェクトをメンバ変数に割り当てる場合は直接割り当てるか次のようにする NSMutableArray *tmp = [[NSMutableArray alloc] initWithObjects:@"hoge", @"foo", nil]; self.array = tmp; [tmp release]; } return self; } - (void)dealloc { // 適切な release self.array = nil; self.message = nil; [super dealloc]; }
プラクティスとして、init〜 メソッドの内部ではプロパティ形式(3.1みたなやつ)でメンバ変数を初期化するのは避けるほうがよいです。