とりあえず、UIButtonの情報をチェック。
 XcodeでChimpanzeeGameViewController.hを開いて、さっき書き込んだUIButtonの部分を選択して右クリック(もしくはコントロールキー+左クリック)だ。そんで出てきたコンテキストメニューで「APIリファレンス内で選択されたテキストを検索」を選ぶ。

Fig.1

と、いつものドキュメントウィンドウが開くわけですわ。ここらへんはヘルプ>APIリファレンス内で選択されたテキストを検索メニューを使っても同じ。

Fig.2

 以前「Xcc>Cocoa」で説明したヘルプ>Xcodeヘルプは、Xcode 3.1になって格段の進化をとげてます。
 リサーチアシスタントとかあるし。

Fig.3

 こいつ開いてる状態でエディタのカーソル移動すると、それに追随して説明文が変わっていく。なかなか便利。

Fig.4

 ま、それはいったん置いといて、UIButtonの調査。
 とにかくrespondToButtonClickで渡されるsenderを調べればどのボタンなのか判る方法が欲しい。まずはPropertiesを調べてみる。これはObjective-C 2.0プログラミング言語 >プロパティで説明されているもの。融通のきくクラスは、たいがい使用者が自由に利用できるプロパティを用意してるもんなんだ~よ。今回はUIButton → UIControl → UIViewとたどって

 tag

ってのを発見。

tag
The receiver’s tag, an integer that you can use to identify view objects in your application.
Discussion
The default value is 0. Subclasses can set this to individual tags.

とか書いてる。ビンゴっぽい。確かにね。用意するとしたらUIViewが適切だわな。
 こいつに各ボタンを識別できる一意の値を設定してみよう。

 あとは、今回のチンパンジーゲームで必要な9つ前後のボタンの用意の仕方なんだけど...
 何言ってんすか、Interface BuilderでViewに全ボタンを配置して、同じように全ボタンのOutletをChimpanzeeGameViewControllerに用意して結びつけるだけっすよ~。
 とか言ったやつ。
 ようこそ筋肉プログラマの世界へ。
 まあ、9つ程度なら、それもありだけどよ~。エレガントじゃないっしょ。発注者が「う~ん、やっぱ9つじゃなく90個にして」とか言ってきたら泣きながら90個配置するわけか?
 ちなみにOutletもIBAction同様、Interface Builderに認識させる方法としてIBOutletというものが用意されている。

  IBOutlet UIButton* button;

と書けば、Interface BuilderのOutlet項目にbuttonってのが表示されます。

Fig.5

 でもIBOutletは配列では持てません。やってみなけりゃ、わかんねーじゃんとChimpanzeeGameViewController.hで

  IBOutlet UIButton* buttons[9];

てやって試したら見事に無視されました。
 無視かよ...
 というわけでChimpanzeeGameViewControllerで直接作成する方法とります(UIViewを継承したCustomViewを作り、この中でボタンを作って、ChimpanzeeGameViewControllerがこれを認識する方法と、ChimpanzeeGameViewControllerでCustomViewに配置する方法なてのがあって、どっちを使うかはグレーゾーンだな。今回はボタンの数、位置関係もChimpanzeeGameViewControllerが制御できるようにChimpanzeeGameViewControllerに実装します)。

 で、このUIButtonの利用例もUICatalogに載ってるんだよね~。
 UICatalogのButtonsViewController.mのcreateRoundedButtonに

  作成方法
  矩形設定方法
  ボタンタイトル設定方法
  アクションへの登録方法

と知りたい事全部使っていました。後はAPIリファレンスで詳細を調べていけばいい。ここで、先に横においていたリサーチアシスタントを使ってみる。


作成方法:buttonWithType

「指定されたタイプの新しいボタンを作る。」

Fig.6

う~ん、おみごとですな。おまけにUIButtonTypeのとこクリックしたら、その部分のAPIリファレンスに飛ぶし。

  [UIButton buttonWithType:UIButtonTypeRoundedRect]

とすれば、ラウンドレクトボタン作成完了っす。UICatalogのButtonsViewController.mでは

  roundedButtonType = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];

とやってるわけですが、これは

  roundedButtonType = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  [roundedButtonType retain];

とやるのと同じ。retainはMemory Management Programming Guide for Cocoa に詳しく説明されてるんだけど。まあ、これから自分が使うから勝手に解放しちゃいかんよという合図を送ってるって程度に承知してください。必要なくなったらreleaseメッセージを送ります。
 で、このretainメソッドの定義が

  - (id)retain

となっててidを返すようになってるからリレーでバトンを渡すように、出力値が次のメッセージの入力値に引き継がれ
Fig.7
てふうになって

  roundedButtonType = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];

という書き方ができるわけですな。

矩形設定方法:

 ButtonsViewController.mのcreateRoundedButtonにある

  roundedButtonType.frame = CGRectMake(0.0, 0.0, kStdButtonWidth, kStdButtonHeight);

てのがそれなんだけど、さすがに「.frame」じゃ出ないな。UIButton上にカーソルを持っていって出てきたUIButton Class Referenceをクリックして調べるしかないね(ちなみにこの「.frame」て書き方はObjective-C 2.0プログラミング言語 >メッセージングの仕組み>プロパティ>ドット構文を参照)。で、ここのPropertiesを見てみるけど見つからない、親クラスのUIControl、UIVewとたどって、ようやくframeが見つかるわけですわ。これによるとこのUIViewが貼付けられる先のUIView上の座標でこのUIViewの矩形を設定とある。

roundedButtonType.frame = CGRectMake(0.0, 0.0, kStdButtonWidth, kStdButtonHeight);

は、座標[0,0]に幅=kStdButtonWidth、高さ=kStdButtonHeightでボタン矩形を設定というわけですな。CGRectMakeの方はリサーチアシスタントできっちり確認できます。


ボタンタイトル設定方法:setTitle

 ではUIControlStateNormalで指定してるな。これUIControlStateHighlightedとかを指定するとボタン押されたときに文字列が変わるのかな~。


アクションターゲット設定方法:addTarget

 これが今回の目玉、Interface Builder抜きでChimpanzeeGameViewControllerのActionであるrespondToButtonClickにUIButtonを結びつける方法。

 addTarget:通知先インスタンス
 action:そのインスタンスのメソッド識別子
 forControlEvents:どういったイベントで呼び出したかの識別子

となっている。メソッド識別子の取り出し方はObjective-C 2.0プログラミング言語 >メッセージングの仕組み>セレクタを参照。今回なら

  @selector(respondToButtonClick:)

と指定すればいいてことになる。最後はどういったイベントかなんだけど、これはそのまま

  UIControlEventTouchUpInside

でいいでしょう。興味がある人は動くようになってから、定数をいろいろ変えてみて試してみたらいい。

 残るはどのタイミングでボタンを作るかなんだけど、自動作成されたChimpanzeeGameViewController.mをよく見ると

/*
Implement loadView if you want to create a view hierarchy programmatically
- (void)loadView {
}
*/

てのがあるわけですわ。ビューを読み込みとか、いかにもなメソッド名なんで調べるとサブクラスは呼び出すべきではないとか書いてるし~。で、その下の

/*
Implement viewDidLoad if you need to do additional setup after loading the view.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/

を調べるとカスタマイズしたいならloadViewの代わりにこっちを使えって書いてる。ちゅーことで、こいつを使う事として以下を追加してみます。

UIButton* bt = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
[bt setTitle:@"?" forState:UIControlStateNormal];
[bt setFrame:CGRectMake(0,0,40,40)];
[bt addTarget:self action:@selector(respondToButtonClick:) forControlEvents:UIControlEventTouchUpInside];

自分が管理するUIViewである_view(これはInterface Builderで設定済み)にaddSubviewでボタンを登録したら、UIViewが内部でretainを呼び出してるので、自分の方は用がないということでreleaseを呼び出して完了。

[_view addSubview:bt];
[bt release];

これでコンパイルして実行。
おお、さっきいじってたボタンに追加されて「?」ボタンが出た。

Fig.8

で、それに最初に調べたtagを使ってみる事にする。tagに1を設定

bt.tag = 1;

しrespondToButtonClickメソッドで受け取ったsenderのtagをボタンのタイトルに設定し直す。stringWithFormatとかは自分で調べてくれ。

- (IBAction)respondToButtonClick:(UIButton*)sender {
NSInteger tag = sender.tag;
[sender setTitle:[NSString stringWithFormat:@"%d", tag] forState:UIControlStateNormal];
}

で、コンパイルして実行、3つのボタンを押していくと~

Fig.9

ちゃんと自分が作ったボタンだけ「1」になって残りは「0」になる。
tag使えるじゃ~ん。
以下次回。
------------
サンプルプロジェクト:Chimpanzee-00.zip