fkm blog

software開発に関することを書いていきます

TableViewを使ってみる

iOSの世界では一方向のリストのことをTableViewと呼ぶみたい. AndroidでもListFragmentの出番が割と多いので, きっとこいつの出番も多そう.

ぐぐるApple公式のPDFが出てくるので, ちゃんと読みたい方はそちらをどうぞ.

手順

  1. StoryBoardにTableViewControllerを貼付ける.
  2. TableViewController用のクラスを追加する.
  3. 必須のdelegate methodを実装する

1. StoryBoardにTableViewControllerを貼付ける.

ドラッグしてぽいっと放り込むだけ.

NavigationControllerから矢印が伸びてないといろいろ困るのでセットで追加しておく.

2. TableViewController用のクラスを追加する

ぽいっと放り込んでもスーパークラスのUITableViewControllerが関連づけされるので, 独自のクラスを追加する.

この時, 親クラスをUITableViewControllerにしておくと, いろいろ勝手にメソッドを追加してくれる.

公式PDFによると, TableViewしかないページの時だけUITableViewControllerを使いましょう ということになってる. ListFragmentのようなカスタマイズはおすすめではないみたい.

3. 必須のdelegate methodを実装する

UITableViewControllerを継承させておくと, Xcodeが勝手にメソッドを追加してくれているはず.

多分こうだろうと想像で書いてみる.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    
    // Configure the cell...
    cell.textLabel.text = self.data[indexPath.row];
}

numberOfSectionsInTableView:はセクション数を返せばいいっぽいので, とりあえず1を返して1セクションだけあるよーと伝える.

tableView:numberOfRowsInSection:はセクション毎の行数を返せばいいみたい. 1セクションだと要素の個数を返せばOKですな.

実行

そして実行すると, 怒られる(´・_・`) 自動生成するのなら最初からちゃんと動くのを生成せんかい と言いたくなる.

エラーはこんな感じ

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier Cell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

ぐぐったらQiitaの記事がでてきた.

ただしくはこうらしい

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    // Configure the cell...
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    cell.textLabel.text = self.data[indexPath.row];
    
    return cell;
}

Androidから入った人用に説明してみる.

tableView:cellForRowAtIndexPath:メソッドは, AdapterクラスのgetView()メソッドに対応するもの. 引数はgetView()と違ってpositionしかやってこない.

で2行目の

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

が, getView()の引数で渡されるconvertViewに相当するものをとってくる処理みたい. iOSも同じように使い回ししないとパフォーマンスに問題がでるっぽい.

その次のif文はgetView()を自分で実装するときのテクニックと同じ. cell (= convertView)が取得できなかったら作成する.

cell.textLabel.textな感じで気楽にアクセスできるので, この辺はAndroidのAdapterよりは実装楽かもしれない`