このページは「iPhoneプログラミング入門」(工学社刊、ISBN 978-4-7775-1541-7)を読んで、もっと先へ進んでみたいと思った人への説明です。
次へ->
<-前へ
「次の一歩」一覧へ
最も簡単なテーブルの作り方6
メソッドtableView:numberOfRowsInSection: の実装
フレームワークで与えられるメソッドの考え方
フレームワークで「このメソッドの実装が必要」とされるメソッドは、大抵「我々が中味を書いて、フレームワークがそれを使う」という形で使われます。
引数の具体的な値は、フレームワークがアプリケーションの実行時に与えます。そして、我々が与えた戻り値をフレームワークが使います。
ですから、我々は、以下のことを想像しながら、メソッドを定義するのです。
- 引数には、どんなものが与えられるのか?
- 戻り値はどのように使われるのか?
引数section
引数については、我々がそれをメソッドの中でどう使うのか、あるいは使わないのかを考えます。
このメソッドの引数は、section。「何番目のセクションか」を示します。何番目かはフレームワークが決めます。
でも、今は「最も簡単なテーブル」ですから、セクション数はひとつだけです。ですから、セクションによって何か違った動作をする、ということはありません。すなわち、引数sectionは、この簡単なテーブルを記述するためのメソッドtableView:numberOfRowsInSectionの中には記述しません。
戻り値を決めるための処理
前ページでも議論したように、戻り値は表示させるべきデータの数です。今は3つとわかっていますから、「3」という数値を戻しても、アプリケーションは動きます。でも、それではあまりに芸がないので、「配列theListの要素数」を戻すことにしましょう。これには、NSArrayクラスに定義されているメソッドcountを使います。
メソッドの実装全文
以上のことから、tableView:numberOfRowsInSection:メソッドは、リスト10のように実装します。
リスト10 メソッド tableView:numberOfRowsInSection:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [theList count];
}
メソッド tableView:cellForRowAtIndexPath:の実装
引数indexPath
引数indexPathをiPhoneで使うときには「テーブルの何番目」という情報をサックリ取り出す方法がある、というところまでは、前ページで確認しました。
それが「row」というプロパティです。
NSIndexPathクラスにはそんなプロパティはありません。でも、UIKitフレームワークで定義してくれているのです。このような追加ライブラリを「NSIndexPath UIKit Additions」と呼びます。
と、このことをアタマに入れておけば、あとは常に以下の方針で行けば大丈夫です。
メソッドtableView:cellForRowAtIndexPath: 中では、「indexPath.row」で、「テーブルの何番目」を表す
戻り値を決めるための処理(1)最初は乱暴でゴメンナサイ
メソッドtableView:cellForRowAtIndexPath: では、indexPath.rowで与えられる位置にセルを作成して、そのセルの内容を設定して戻してやります。我々が書くのは、セルをどのように作成するかです。方針としては、以下のように書きます。
UITableViewCell *cell = [
[UITableViewCell alloc] initWithStyle:どんなスタイル reuseIdentifier:適当な識別名
];
作成されるセルはUITableViewCellというクラスのオブジェクトです。それに、 cell という変数名をつけてあります。
これも、本書でやった「文字列」それからこちらの記事でやった「配列」の新規作成と同じような書き方ですね。まず、セルのためにメモリを確保してから、決まった値で「初期化」します。
乱暴というのは、つまりココ
この処理を見て、「このメモリ、あとで解放しないといけないだろうな」と思ったら、それは大変慎重でよいことです。
でも、この最も簡単なテーブルでは、作りっぱなしにしてしまいます。なぜなら、テーブルにおけるメモリの節約方法は、ちょっと「凝っている」からです。その「凝った方法」を学ぶ前に、まず本当に、自分で指定した内容がテーブルに表示されるのかどうか確認したいではありませんか。
データはたった三つですし、テストするのはシミュレータです。ですから、このセルのためのメモリの解放は今は考えません。
戻り値を決めるための処理(2)セルの初期化
セルの初期化には、UITableViewCellに定義されている以下のメソッドを使います。
initWithStyle:reuseIdentifier:
これは二つの処理から成っています。「セルの書式を決める」という「initWithStyle」と、「再利用のための識別名を決める」という「reuseIdentifier」です。
両者は互いに独立ではありません。「なんかこのreuseIdentifierってめんどくさそうだから省略しよう」というのはできないのです。
「initWithStyle」は、どんな書式にするかを引数として指定してやらなければなりません。でも大丈夫。いくつかの「デフォルトのスタイル」が用意されています。そのうち、「UITableViewCellStyleDefault」と指定すれば、iPhoneのデフォルトの書式に設定することができます。「UITableViewCellStyleDefault」は、「UITableViewStyle」というクラスのオブジェクトです。。ゆえにメソッドinitWithStyle:の部分は、以下のようになります。
initWithStyle: (UITableViewCellStyle)UITableViewCellStyleDefault
これに続けて空白を置いて、reuseIdentifier: メソッドを書きます。名前からわかってきましたね。テーブルのセルは、なるべく「使い回す」のです。ただ、その「使い回し方」についてはちょっと説明が長くなりますので、今は「使い回さない」ことにします。
そうすると話は簡単、以下のようにそんな識別名はnil(空)にすればいいのです。
reuseIdentifier:nil
ただし、みなさんの側で「データが少なきゃセルは使い回さなくてもいいんだな」とは思わないでください。あくまで、学習を一歩一歩進めるための、シミュレータ上での開発途上のコードです。
とりあえずセル作成作業の完成
そんな状態ですが、テーブル上のindexPath.rowで与えられる位置におけるセルの作成をまとめると、リスト11のようになります。
リスト11 あくまで開発途上だが、一応セルの作成は完了
UITableViewCell *cell = [
[UITableViewCell alloc]
initWithStyle: (UITableViewCellStyle)UITableViewCellStyleDefault reuseIdentifier:nil
];
作成したセルの「内容」はプロパティのプロパティ
このセルにどういう文字列を表示するか決めます。
「セルに表示する文字列の内容」は、以下のようなUITableViewCellオブジェクトのプロパティで表すことができます。
cell.textLabel.text
cell のプロパティであるtextLabel、さらにそのプロパティであるtext、ということです。
それに文字列を指定することになります。
配列の要素を取り出す
文字列は配列theListの要素を使います。
配列から、インデックスを指定して要素を取り出すには、objectAtIndexメソッドを用います。配列のインデックスがその引数です。
[theList objectAtIndex:インデックス]
インデックスに、indexPath.rowの値を指定します。
[theList objectAtIndex:indexPath.row]
「セルの各文字列を、配列の各要素にする」作業の完成
以上、セルの文字列はリスト12のように決定されます。
リスト12 セルの文字列を決定
cell.textLabel.text=[theList objectAtIndex:indexPath.row];
メソッドの実装全文
以上、現段階での、メソッドtableView:cellForRowAtIndexPath:の実装は、リスト13のようになります。繰り返すようですが、あくまでシミュレータ上でのみ無責任に行えるテスト・コードです。
リスト13 現段階のtableView:cellForRowAtIndexPath:の実装
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [
[UITableViewCell alloc]
initWithStyle:(UITableViewCellStyle)UITableViewCellStyleDefault reuseIdentifier:nil
];
cell.textLabel.text=[theList objectAtIndex:indexPath.row];
return cell;
}