2013/12/8 更新。iOS 7に対応しました。

前回の続き。今回はUITableViewCellのスタイルごとの生成と、スタイルごとにreuseIdentifierを変えるサンプルについて説明します。

サンプル: https://github.com/stack3/UITableViewSamples

サンプルを起動してMultiple Cellsを選択してください。

11

このように異なるスタイルのUITableViewCellが表示されています。スタイルは以下のようにUITableViewCellを生成するときに決定します。

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:reuseIdentifier];

UITableViewCellStyle(セルのスタイル)の種類

  • UITableViewCellStyleDefault: 左画像(imageView)、右文字列(textLabel)
  • UITableViewCellStyleSubtitle: 左画像(imageView)、上文字列(textLabel)、下文字列(detailTextLabel)
  • UITableViewCellStyleValue1: 左画像(imageView)、左寄せ文字列(textLabel)、右寄せ文字列(detailTextLabel)
  • UITableViewCellStyleValue2: 右寄せ左字列(textLabel)、左寄せ右文字列(detailTextLabel)

前回、セルの再利用について説明しました。今回は、複数のスタイルのUITableViewCellを表示するので、スタイルごとにreuseIdentifierを変える必要があります。異なるスタイルのUITableViewCellを再利用してしまうと表示が意図しないものになります。

STMultipleCellRowクラス

このクラスで行のデータを管理します。プロパティは以下のようになっています。

// セルのスタイル
@property (nonatomic) UITableViewCellStyle cellStyle;
// タイトル
@property (strong, nonatomic) NSString *title;
// 詳細
@property (strong, nonatomic) NSString *detail;
// 画像
@property (strong, nonatomic) UIImage *image;

スタイルによって異なるreuseIdentifierを返すメソッドを持ちます。

- (NSString *)reuseIdentifier
{
    if (_cellStyle == UITableViewCellStyleDefault) {
        return @"Default";
    } else if (_cellStyle == UITableViewCellStyleSubtitle) {
        return @"Subtitle";
    } else if (_cellStyle == UITableViewCellStyleValue1) {
        return @"Value1";
    } else { // UITableViewCellStyleValue2
        return @"Value2";
    }
}

STMultipleCellsViewController

initメソッドで行データを生成します。4スタイルx10=40個の行データになります。

_rows = [NSMutableArray arrayWithCapacity:30];
for (int i = 0; i < 10; i++) {
    STMultipleCellRow *row = [[STMultipleCellRow alloc] init];
    row.cellStyle = UITableViewCellStyleDefault;
    row.title = [NSString stringWithFormat:@"Title %d", i];
    row.image = [UIImage imageNamed:@"castle01.jpg"];
    [_rows addObject:row];

    row = [[STMultipleCellRow alloc] init];
    row.cellStyle = UITableViewCellStyleSubtitle;
    row.title = [NSString stringWithFormat:@"Title %d", i];
    row.detail = @"Detail";
    row.image = [UIImage imageNamed:@"castle02.jpg"];
    [_rows addObject:row];

    row = [[STMultipleCellRow alloc] init];
    row.cellStyle = UITableViewCellStyleValue1;
    row.title = [NSString stringWithFormat:@"Left %d", i];
    row.detail = [NSString stringWithFormat:@"Right %d", i];
    row.image = [UIImage imageNamed:@"castle03.jpg"];
    [_rows addObject:row];

    row = [[STMultipleCellRow alloc] init];
    row.cellStyle = UITableViewCellStyleValue2;
    row.title = [NSString stringWithFormat:@"Left %d", i];
    row.detail = [NSString stringWithFormat:@"Right %d", i];
    [_rows addObject:row];
}

dequeueReusableCellWithIdentifier:とdequeueReusableCellWithIdentifier:indexPath:の使い分け

前回のサンプルでは、

  • UITableView#registerClass:forCellReuseIdentifier:
  • UITableView#dequeueReusableCellWithIdentifier:indexPath:

を使っていました。

UITableView#dequeueReusableCellWithIdentifier:indexPath:は、UITableView#registerClass:forCellReuseIdentifier:でセルのクラスを登録することを前提としています。UITableView#dequeueReusableCellWithIdentifier:indexPath:は引数から判断して、セルオブジェクトを必要に応じて生成して返します。必要ない場合は既存のセルオブジェクトを再利用して返します。

UITableView#dequeueReusableCellWithIdentifier:indexPath:は、UITableView#registerClass:forCellReuseIdentifier:でセルクラスの登録が行われていないとアプリがクラッシュしてしまいます。

今回はスタイルをDefault以外も使っています。セルのスタイルは初期化メソッドのUITableViewCell#initWithStyle:reuseIdentifier:で指定する必要があります。セルを生成した後にスタイル変更はできません。よってUITableView#registerClass:forCellReuseIdentifier:とUITableView#registerClass:forCellReuseIdentifier:を使うことはできません。

こういった場合は、tableView:cellForRowAtIndexPath:でUITableView#dequeueReusableCellWithIdentifier:を使います。このメソッドはセルクラスの登録なしで使うことができます。再利用するセルオブジェクトがない場合は、nilを返します。nilを返した場合は、UITableViewCell#initWithStyle:reuseIdentifier:でオブジェクトを生成すればよいのです。

tableView:cellForRowAtIndexPath:の実装

上記に従い実際の実装は以下のようになります。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    STMultipleCellRow *row = [_rows objectAtIndex:indexPath.row];
    // スタイルに合わせたreuseIdentifierから、再利用できるセルがあれば取得
    UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:row.reuseIdentifier];
    if (cell == nil) {
        // 再利用可能なセルがなければ、スタイルを指定してセルを生成する
        cell = [[UITableViewCell alloc] initWithStyle:row.cellStyle reuseIdentifier:row.reuseIdentifier];
    }
    //
    // 行データの各項目をセルへ代入します
    //
    cell.textLabel.text = row.title;
    cell.detailTextLabel.text = row.detail;
    cell.imageView.image = row.image;

    return cell;
}

その3へ続く