このページは「iPhoneプログラミング入門」(工学社刊、ISBN 978-4-7775-1541-7)を読んで、もっと先へ進んでみたいと思った人への説明です。

次へ->
<-前へ
「次の一歩」一覧へ

最も簡単なナビゲーションの作り方3

セルを選ぶと...を記述するメソッド

自動記入されたメソッドtableView:didSelectRowAtIndexPath

「ナビゲーション・ベース」のテンプレートを採用したことによって、「テーブル」関係のメソッドが自動で記入してもらえました。その中には、まだ我々が使っていないメソッド、tableView:didSelectRowAtIndexPathがあります。読んで字の如し、これがテーブルのセルを選んだときの動作です。
リスト6 自動記入されたメソッドtableView:didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
	/*
	 <#DetailViewController#%> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
     // ...
     // Pass the selected object to the new view controller.
	 [self.navigationController pushViewController:detailViewController animated:YES];
	 [detailViewController release];
	 */
}

「中身」はしかし、「/*...*/」記号で「コメントアウト」されています。ですから、今はセルをクリックしても、何も起こりません。

自動記入の中身(1)移動先のビューをオブジェクトとして作成

まず、これです。
 <#DetailViewController#%> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];

「<#DetailViewController#%>」の「記号」は、「たとえばDetailViewController とかいうビュー・コントローラがあったらそれを使え」という意味で書いてあります。それが、「移動先」のビューの名前です。 そして、おなじみのこの形です。
 [ [ ナントカクラス alloc] initWithナントカ: どんなナントカか ]
つまり、 たとえばDetailViewControllerというクラスのオブジェクトを作るという作業です。このクラスは、別途自分で作ってあることが想定されています。

じゃあ作っちゃいましょう

この先長々と「別途自分で作ってあるはずのビューコントローラ」について議論するのは歯がゆいものがあるでしょう。とにかくひとつ作ってしまいましょう。セル「Red」を選んだときに移動する「RedViewController」です。

プロジェクトに「MyViews」グループを作成

本書でも実感したと思いますが、Xcode3.2で作成するファイルの「置き場所」というのは結構いい加減です。あまり考えずに作ると何もかもがそのへんのフォルダにゴロゴロ置かれてしまいます。是非、将来のバージョンでは改善してもらいたいものです。
せめて、プロジェクトの中だけでも、見やすくして作業しましょう。ということで、今作業中のプロジェクト「FirstNav」の「グループとファイル」欄を操作して、プロジェクト「FirstNav」の下に「MyViews」グループを作成します。これには、「グループとファイル」欄の一番上の「FirstNav」アイコンを右クリックして「追加」-「新規グループ」を選びます。

「MyViews」グループに、新規ファイルを作成

作成された「MyViews」グループを右クリックして、今度は「新規ファイル」を選びます。

新規ファイルのテンプレート選択画面になります。まず、左側の一覧は「iOS」-「Cocoa Touch Class」になっていますね。その条件で、右側で選ぶのは、「UIViewController subclass」です。
下側の「オプション」をみてください。「With XIB for user interface」にチェックがついていることを確認します。そして「次へ」進みます。

ファイル名を「RedViewController」にします。「同時に"RedViewControllerR.h"も作成」にチェックがついていることを確認します。保存場所は、もうめんどくさいですから適当でいいです。「完了」ボタンで作業を終えます。

「グループとファイル」欄の「MyViews」グループの中に「RedViewController.h」「RedViewController.m」「RedViewController.xib」の3つができます。

背景だけを赤くしておこう

この「RedViewController」は「どこかへ移動することを確かめる」だけのファイルですから、プログラムの編集はしません。「背景」だけ赤くしておきましょう。と、いうことは、「RedViewController.xib」だけを編集します。インターフェイス・ビルダー上で、「View」の「属性インスペクタ」ウィンドウを操作します。「Background」の色を赤くするのです。それだけです。

これで、具体的に「RedViewControllerクラス」を考えればよくなりました。

どのセルを選んでも「RedViewController」のビューに行くことにする

RootViewController.mの編集に戻る

「RedViewController」を作成したので、Xcodeの編集画面はRedViewController.hなどに切り替わっているかも知れません。「RootViewController.m」の編集画面に戻りましょう。

<#DetailViewController#%>をRedViewControllerに変える

リスト6に<#DetailViewController#%>と書いてある部分をRedViewControllerに変更します。記号はもうなくなります。

<#NibName#%>をRedViewControllerに変える

同じ行にある<#NibName#%>もRedViewControllerに変えます。

detailViewControllerをnextViewControllerに変える

クラスの名前がDetailViewControllerでなくなったのに、変数名がdetailViewControllerでは違和感がありますね。
今は、テーブルのどのセルを選んでも、「RedViewこの「移動先のビュー」は将来的にRedViewControllerだけではなくするつもりですから、変数名はnextViewControllerにしておきます。

全体をアンコメントする


改めてみてみよう

改めて、メソッドtableView:didSelectRowAtIndexPathを見てみましょう。リスト7のようになります。
リスト7 tableView:didSelectRowAtIndexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    	
	 RedViewController *nextViewController = [[RedViewController alloc] initWithNibName:@"RedViewController" bundle:nil];

	 [self.navigationController pushViewController:nextViewController animated:YES];
	 [nextViewController release];
	 
}

自動記入の中身(2)移動先のビューオブジェクトは「Nibファイルを用いて」作成

ヘンな記号がなくなったし、文字色が緑一色からハイライト表示になったので、中身がより見やすくなりましたね。そこで、RedViewControllerクラスのオブジェクトを作成する記述をもう一度確認すると、以下のような記述になっていることがわかります。
[[RedViewController alloc] initWithNibName:@"RedViewController" bundle:nil]
initWithNibName:というのが実質上の「初期化」メソッドです。つまり、オブジェクトを作成するときに、その外観についてはどのNIBファイルを読み込めばよいかを指定するのです。RedViewControllerクラスのオブジェクトなんだからRedViewController.xibなのは当たり前じゃないかと思うかも知れませんが、まぁ今のところは指定する必要があるのです。拡張子は要りません。

もうひとつ、bundle: と書いてあるのは、「bundleを指定しなさい」ということで、文法的にはメソッドです。「bundle」とは、iPhoneプログラミングでは、「FirstNav」のような、アプリケーションのことです。他のアプリケーションにあるNIB ファイルを使う場合は、指定します。多くの場合は、自分のアプリケーションにあるファイルを使うでしょう。その場合、nilを指定します。

プロパティnavigationControllerを使う

そのあとが「ナビゲーション」です。
[self.navigationController.....
selfは、RootViewControllerクラスのシングルトン・オブジェクトです。本書でもフツーに使ってきた「ビューを記述するクラス」、すなわち「UIViewController」クラスを継承するクラスです。
実は、「UIViewController」クラスにはすでにnavigationControllerというプロパティが用意されています。もちろん、UINavigationControllerクラスのオブジェクトです。ですから、突然このように切り出しても、コンパイルエラーにならないのです(selfも要らないかと思ったのですが、あいにくselfがないとコンパイルエラーになりました)。
「コンパイルエラー」にはなりませんが、別途UINavigationControllerクラスのオブジェクトを作らなければ、結果はnil、空っぽですから、十中八、九は「実行エラー」になるでしょう。でも、「ナビゲーションベースのテンプレート」ですから、それはちゃんと作られています。どこで作られているかというと、FirstNavAppDelegateクラスの定義の中です。それは、アプリケーションの動作を確認できたら、確認していきましょう。

このnavigationControllerに対して、pushViewController:animated:メソッドを使います。
そのあとに、以下の記述があります。
 [nextViewController release];
nextViewControllerは、移動先のビュー・オブジェクトとしてこのメソッド中で作成したものです。ここでrelease、すなわち「あとはおまかせという指定」をしておくことにより、このページからまた別のページに切り替わるときに、アプリケーションなりシステムなりが適当にメモリを解放してくれます。 すごいですね。テーブルの作成、そしてテーブルのセルをクリックしたときの動作、すべてゼロから我々が書き始めるとなると大変です。でも、「ナビゲーションベースのテンプレート」を利用すれば、ほとんどのコードはできていて、我々の都合に合わせてちょこちょこっと書き換えればいいだけになるのです。

RedViewControllerクラスの情報を教える

ただしひとつ大事なことをまだやっていません。それは、別途作成したRedViewControllerクラスの情報を、今編集中のRootViewControllerクラスに教えてやることです。
それには、冒頭に「#import」を書いてやります。リスト8のようになります。
リスト8 RedViewController.hをimportする
#import "RootViewController.h"
#import "RedViewController.h"

起動してみよう

ファイルを保存したら、ビルド・実行してみましょう。
テーブルが現れたら、「Red」の欄をタッチ(シミュレータなので、クリック)してみます。真っ赤な画面にニュルンと切り替わったら、成功です。
元に戻す方法は...実は、まだ記述していません。それには、このアプリケーション全体のしくみを研究する必要があるのです。
「ナビゲーションコントローラ」はどこで作られているのか?その謎を明らかに。