Objective-C では、オブジェクトの生成に alloc と init などのイニシャライザを組み合わせて使うというのは、ちょっとでもかじったことがある方はご存じでしょう。
MyObject *obj = [[MyObject alloc] init];
今日はこの仕組みについてです。まず、この alloc-init について2つのポイントを挙げておきます。
- 呼出し側はイニシャライザの戻り値を使うことになっている
- イニシャライザはクラスのインスタンスメソッドとしてプログラマが追加/オーバーライドできる
Objective-C ではこのことが言語の基本として存在しているおかげで、オブジェクト生成の柔軟性がぐっと上がっています。イニシャライザはプログラマが実装するので、どのようなインスタンスを返すかは自由です。上記の例で言えば MyObject の init は、MyObject そのもののインスタンス以外を返しても良いということです。
実際、NSString や NSData といった主要クラスの一部は、どのようなイニシャライザを使うかによって、想定される用途に適したサブクラスのインスタンスが生成されるようになっています(クラスクラスタと呼ばれる仕掛けですが、これについてはまたいずれ)。
同じように、自分で実装するクラスでもイニシャライザの実装を工夫すれば、引数や状況に応じた別クラスのインスタンスを返せます。いわば、GoF のデザインパターンにある Abstract Factory のような仕組みが最初から組込まれているわけで、自然な記述で生成オブジェクトの抽象化を実現できます。イニシャライザに限らなくても、Objective-C では [NSString string] のような簡易コンストラクタも一般的に利用されるので、こちらでもプログラマが好きなように生成処理を記述できます。
最近なら、iPhone / iPad の Universal アプリケーションで、呼出し側には影響を与えずに各デバイスに特化したインスタンスを返すというケースも考えられますね。
GoF のデザインパターンでも多く取り上げられていることからわかるように、「オブジェクトの生成」はオブジェクト指向プログラミングにおいて大きなウェイトを占めます。その部分が言語の基本として柔軟にできているというのは、Objective-C の大きな特徴だと感じています。
というわけで、はじめは面倒だと感じていた “alloc-init” に感謝できるようになってきた今日このごろです。