ポインタのポインタ

ポインタのポインタは何のために使うか良くわからなかったけど、使ってみると意外と便利だった。

例えば何か変数の初期化をするような関数を作るとする。

- (void) createView:(UIView*)view1 otherView:(UIView*)view2
{
	// なんか処理
	view1 = [[UIView alloc] initWithFrame:CGRectZero];
	view2 = [[UIView alloc] initWithFrame:CGRectZero];
}

この関数は2つのビューを作成するもの。2ついっぺんに return することはできないので、もらったポインタにたいして処理をするものとする。
そうすると、上の書き方だと問題がある。例えば、下のようにこの関数を使うとする。

- (void)hoge
{
	UIView *view1, *view2;
	[self createView:view1 otherView:view2];
	NSLog(@"view1:%@ view2:%@", view1, view2);
}

実はこのように使うと、5行目のログはnilが出力されるはず。createView 内で alloc しているので、新しいメモリアドレスで UIView の分のメモリを確保するのだ。元のポインタ変数の指し示すアドレスは変わらないため、元のポインタには変更が反映されない。
そこで、ポインタのポインタを使う。ポインタのポインタからポインタに対して操作すると、ちゃんとポインタに変更が反映される。何言ってるかわからないと思うけど、下のコードを見て欲しい。自分もObj-Cやり始めてひが浅いのでうまい説明の仕方があれば是非教えてください。

// 引数にポインタのポインタを指定
- (void) createView:(UIView**)view1 otherView:(UIView**)view2
{
	// 処理するときにはポインタを操作
	*view1 = [[UIView alloc] initWithFrame:CGRectZero];
	*view2 = [[UIView alloc] initWithFrame:CGRectZero];
}

- (void)hoge
{
	UIView *view1, *view2;
	// 関数にはポインタのアドレスを渡す
	[self createView:&view1 otherView:&view2];
	NSLog(@"view1:%@ view2:%@", view1, view2);
}

こんな感じで書けば呼び出し元の変数にも変更が反映される。Flyweightパターンとか、この書き方知らないとしんどくなりそう。