ガベージコクレションへの移行
ここまでガベージコレクションの使い方、概念、動作を説明してきた。正直、ガベージコレクションの導入には何も必要ない、ということが分かっただろう。ガベージコレクションが有効ならば、ほぼ何も気にすることなく、ソースコードを書いてしまえばいい。
だがこれは、「新規」に、「Leopard専用」のアプリケーションを書くときに限られる。実際には、今までに書いたコードを使い続けなくてはいけないことも多い。そのようなコードをガベージコレクションで動作させるときなどに、気を付けておきたいものをまとめておこう。
retain/release/autoreleaseは無効
ガベージコレクションを有効にすると、retain、release、autoreleaseといったメソッドは無効になる。従って、これらのメソッドを使っているソースコードでも、何の変更もすることなく、ガベージコレクションの恩恵を受けることが出来る。
無効化されていることは、簡単なコードで検証することができる。たとえば、次のようなコードを実行してみよう。
MyObject* object;
object = [[MyObject alloc] init];
[object release];
[object release];
releaseを2回呼んでいる。ガベージコレクションが無効ならば、すでに解放されたオブジェクトをもう一度解放しようとしているので、当然のごとくクラッシュする。だがガベージコレクション有効の場合、releaseは単に無視されるので、何も起こらない。
逆にいうと、ガベージコレクションが有効の場合は、releaseを呼んだだけでは解放されないので注意が必要である。たとえば、次のコードを考える。
static MyObject* object;
- (void)createAndRelease
{
object = [[MyObject alloc] init];
[object release];
// この段階では解放されない
// nilを代入することで解放される
object = nil;
}
MyObjectの確保と解放をするだけのメソッドだ。objectをallocした後、releaseを呼んでいるのだが、この時点ではreleaseの呼び出しは無視されるだけなので、オブジェクトは解放されない。その後、objectにnilを代入することで、参照がなくなり解放が行われる。
これからソースコードを書くときは、ガベージコレクション無しで動作させる場合でも将来の移行を見越して、releaseした後は変数にnilを代入しておくといいかもしれない。
finalizeとdealloc
Objective-C 1.0では、オブジェクトが解放されるときにdeallocメソッドが呼ばれ、終了処理などをこのメソッドで行っていた。Objective-C 2.0では、deallocの代わりとしてfinalizeメソッドが導入された。ガベージコレクションが有効になっている場合は、このメソッドを上書きして終了処理をすることになる。
ところで、deallocメソッドで行う処理では、重要なものは保持しているインスタンス変数の解放だった。だが、finalizeではこれを行う必要はない。いや、やるべきではない、と言うべきか。finalizeが呼ばれるのは、ガベージコレクションの最中ということになる。ということは、finalizeが呼ばれたオブジェクトが参照しているオブジェクトは、すでにガベージコレクションの対象になっているはずだ。従って、参照しているインスタンス変数にreleaseメソッドを送ったり、nilを代入したり、という種類の処理をやる必要は、まったくない。finalizeでは、それ以外の終了処理を記述しよう。
それに加えて、上書きしたfinalizeの中で[super finalize]を呼び出すことも忘れずに。
強い参照と弱い参照
あるオブジェクトがガベージコレクションの対象になるかどうかは、ルートオブジェクトから参照されているかどうかで決まる。だが、時には、あるオブジェクトへの参照を持ちたいが、これをガベージコレクションの判定に使わせたくない、という場合もあるだろう。
そこで、参照には2種類のタイプがある。それぞれ、強い参照(strong reference)と弱い参照(weak reference)と呼ばれる。強い参照はガベージコレクションのときに考慮され、弱い参照は考慮されない。
普通に変数に代入を行うと、強い参照になる。弱い参照を行うには、__weakキーワードを使う。
@interface MyObject : NSObject
{
__weak NSString* friend;
}
@end
弱い参照を使うコレクションクラス
ガベージコレクションを使うときは、辞書や配列といったコレクションクラスにも気を遣わなくてはいけない。不用意にこれらのコレクションクラスにオブジェクトを挿入すると、強い参照が発生するので、明示的に削除しない限り、ガベージコレクションの対象にならなくなるからだ。
そこで、新たなコレクションクラスが追加された。挿入されたオブジェクトに対して、弱い参照を持つクラスだ。NSMapTableとNSHashTableになる。NSMapTableはNSDictionaryの、NSHashTableはNSSetの代替物と考えてほしい。使用出来るメソッドは、ほぼ同じだ。挿入されたオブジェクトに対して、強い参照になるか、弱い参照になるかが違う。