カスタム検索

2008年12月21日日曜日

Objective-Cにおけるメモリ管理なんて怖くない!その2

前回、retain , release と dealloc でインスタンスのメモリ管理をやりました。
deallocで関連するインスタンスの解放をするのは良いとしても、 release 自体も忘れてしまったりする事があります。

Objective-Cでは autorelease という仕組みがあるそうなのでそこを見ていきます。
NSAutoreleasePool クラスを使って実現します。
NSAutoreleasePool は、自動解放されるべきインスタンスを保持しておくクラスです。
クラスが定義されると、 autorelease対象の広場(プール)が作成されます。
広場が存在する状態で、他クラスのインスタンスに autorelease を送ると、そのインスタンスは広場にほうりこまれます。
(広場に存在するだけで参照されているわけではないので、インスタンスのリファレンスカウンタは変わらない)

広場の release を実行すると、広場に存在するインスタンスすべてに release が実行されます。


id pool=[[NSAutoreleasePool alloc] init]; // 広場の作成

id foo=[[Foo alloc] init]; // Fooクラスのインスタンス作成。foo のリファレンスカウンタは1
[foo autorelease]; // foo インスタンスを広場に登録する。リファレンスカウンタは1のまま

[pool release]; // foo にもreleaseが実行される


NSAutoreleasePool は、複数存在してもよい。
複数存在する場合に autorelease を実行した場合は、一番近い所で指定されたプールへほうりこまれる。
基本は開始と終了でメインの pool を作り、内部でループなど一時的なインスタンスを作成する場所で子プールを作成する。


id mainPool=[[NSAutoreleasePool alloc] init];

id hoge=[[Hoge alloc] init];
[hoge autorelease]; // mainPool へ登録される

while(条件) {
id subPool=[[NSAutoreleasePool alloc] init];

id foo=[[Foo alloc] init];
[foo autorelease]; // subPool へ登録される

[subPool release];
}

[mainPool release];


CocoaのGUIアプリケーションはNSApplicationがイベント発生時(マウスクリック等)に子プールを作成して、イベント終了時にreleaseしてくれるので、それほど気にしなくても自動でやってくれる。
iPhoneSDKもそうなのかな?


・オーナーシップとメモリ管理
init~~ で呼ばれるメソッドはオーナーシップが定義される。(メモリの管理をする必要がある)
同等のメソッドで init がない場合は一時的なインスタンスとなり、 autorelease に登録される。

例:文字列を扱うNSStringクラスの場合

-(id)initWithUTF8String:(const char *)bytes
+(id)stringWithUTF8String:(const char *)bytes

どちらも文字列を保持するオブジェクトが作成されるが、initは生成したオブジェクトがオーナーとなり、
stringはプールへ登録される(autoreleaseが実行される)

オーナーシップを与えないコンストラクタをコンビニエンスコンストラクタと呼ぶ。

・シングルトンの定義
定数やシングルトンを作成する為には、retain,release,retainCountの機能を上書きする必要がある。
retainとreleaseを何もしないメソッドにし、retainCountは常に UINT_MAX を返すようにする。

0 件のコメント: