第6章【テーブルのパターン】を読む ーあるいは、葛藤との闘いー

投稿者: | 2011/03/20

結局、本の内容をなぞるだけの状態になっていて、
こんなのEvernoteにやっとけよ状態なのが心に痛い今日この頃です。

iOS開発におけるパターンによるオートマティズム

木下 誠 (単行本 – 2011/2/9)
¥ 2,940


と言うわけで、今回読む章は…

6 テーブルのパターン

テーブルは、iPhoneでいちばんよく見かけるユーザーインタフェース。
便利で多機能だが、それゆえに複雑なプログラミングを要求される。

6.1 テーブルとは

6.1.1. テーブルはiPhoneの中心

テーブルビューの特性について書いてある。

6.1.2. UITableView と UITableViewCell

テーブル全体がUITableViewで、各行がUITableViewCell。 *01まあ、名前見れば想像はつく
ポイントは、UITableViewCellが、
Cocoa touchのビューの中では、ちと特殊であるということ。

一般的にCocoa touchのビューはサブクラス化を行わない。
理由は、挙動の制御や拡張はデリゲートで行うという思想から。

ただ、例外的にUITableViewCellは、サブクラス化されることを前提にしている。

6.1.3. テーブルのMVC

テーブルプログラミングのMVC構造について。
ビューがUITableViewとUITableViewCell。
コントローラがUIViewController。
モデルがモデルマネージャ。

ポイントは、UITableViewCellとインスタンスが1対1にならないこと。
理由はメモリの節約。
セルのインスタンスは最小限に抑え、使い回す。

よって、UITableViewCellは直接モデルと結びつけてはならず、
モデルマネージャを介してデータを取得する。

6.2 セルのパターン

6.2.1. 標準のセル

セルは様々にカスタム化して使用する。
その前に、標準のセルスタイル4つと右端に表示するアクセサリを紹介。

6.2.2. contentView と backgroundView

カスタムセルの作成について。
UITableViewCellのサブクラス構造を説明。
目的に応じて、どのサブクラスに手を入れるかを考える。

6.2.3. サブビューの作成

実際に、サブビューをカスタマイズして、RSSチャンネルの情報を表示するビューを作る。

1)UITableViewCellのサブクラスを作る。
名前はRSSCell。
インスタンス変数として宣言し、作成したサブビューへの参照を保持する。

@interface RSSChannelCell : UITableViewCell {
    // サブビュー
    UILabel* _titleLabel;
    UILabel* _feedLabel;
    UIImageView* _numberBackgroundImageView;
    UILabel* _numberLabel;
}
@end


2)初期化メソッドを実装する。
initWithStyle:reuseIdentifier:を上書き。
その中でサブビューのインスタンス化を行う。
同時にcontentViewにaddSubView:を使ってビュー階層への追加も行う。

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier {
    // 親クラスの初期化メソッドを呼び出し
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if ( !self ) {
        return nil;
    }
    
    // title ラベルの作成
    _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    _titleLabel.font = [UIFont systemFontOfSize:16.0f];
    _titleLabel.textColor = [UIColor blackColor];
    _titleLabel.highlightedTextColor = [UIColor whiteColor];
    [self.contentView addSubview:_titleLabel];
    
    // feed ラベルの作成
    _feedLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    _feedLabel.font = [UIFont systemFontOfSize:12.0f];
    _feedLabel.textColor = [UIColor grayColor];
    _feedLabel.highlightedTextColor = [UIColor whiteColor];
    [self.contentView addSubview:_feedLabel];
    
    // UIImageView の作成
    UIImage* image;
    image = [UIImage imageNamed:@"numberBackground.png"];
    _numberBackgroundImageView = [[UIImageView alloc] initWithImage:image];
    [self.contentView addSubView:_numberBackgroundImageView];
    
    // 数字ラベル作成
    _numberLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    _numberLabel.font = [UIFont systemFontOfSize:17.0f];
    _umberLabel.textColor = [UIColor whiteColor];
    _numberLabel.backgroundColor = [UIColor clearColor];
    _numberLabel.textAlignment = UITextAlignmentCenter;
    [self.contentView addSubview:_numberLabel];
    
    return self;

サブビューのインスタンス化にはinitWithFrame:を使用。
この段階ではインスタンス化を行うのみで、領域サイズも0で構わない。

また、作成したインスタンスに対してautoreleaseを呼んでいない点にも注意。
これはdeallocで解放を行う。

6.2.4. コンテンツのためのアクセッサメソッド

作成したサブビューに値を設定するための、アクセッサメソッドを用意する。
方法は2つ。

1)追加したサブビューを、そのままプロパティとして提供する。

    // サブビューのためのアクセッサ
    @property (nonatomic, readonly) UILabel* _titleLabel;
    @property (nonatomic, readonly) UILabel* _feedLabel;

実装は @synthesize を使ってプロパティメソッドを作成する。

    // プロパティの実装
    @synthesize titleLabel = _titleLabel;
    @synthesize feedLabel = _feedLabel;

利点は、コントローラ側で細かくサブビューの状態を制御できること。
欠点は、値を設定した際の再レイアウトを自前で行う必要があること。

2)コンテンツ自体を表すオブジェクトへのアクセッサを提供する。

    // コンテンツのためのアクセッサ
    @property (nonatomic) int itemNumber;

実装はアクセッサメソッドを上書きして行う。

- (int)itemNumber {
    // ラベルから数値を取得
    return [_numberLabel.text intValue];
}

- (void)setItemNumber:(int)itemNumber {
    // ラベルにテキストを設定
    _numberLabel.text = [NSString stringWithFormat:@"%d", itemNumber];
    
    // セルの再レイアウト
    [self setNeedsLayout];
}

利点は、値を設定すると同時に再レイアウトを行えること。
欠点は、アクセッサメソッドの上書きをしてやる必要があること。

6.2.5. サブビューのレイアウト

作成したサブビューのレイアウトについて。
レイアウトはlayoutSubviewsメソッド内で行う。
初期化やアクセッサの中では行わない。

- (void)layoutSubviews {
    // 親クラスのlayoutSubviewsを呼び出す
    [super layoutSubviews];
    
    // contentViewのサイズを取得
    CGRect bounds;
    bounds = self.contentView.bounds;
    
    // titleLabelのレイアウト実行
    ...
    
    // feedLabelのレイアウト実行
    ...

6.2.6. セルのハイライト⁄選択

カスタマイズしたサブビューでの、ハイライトや選択状態表示について。
標準のセルは、既にこの機能を持っているので、
カスタマイズしたサブビューでも、これを上書きして使用する。

- (void)setHighlighted:(BOOL)highlighted animated:animated {
    // 親クラスのsetHighlighted:animatedを呼び出し
    [super setHighlighted:selected animated:animated];
    
    // ラベルのハイライトを設定
    _titleLabel.highlighted = highlighted;
    _feedLabel.highlighted = highlighted;
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    // 親クラスのsetSelected:animatedを呼び出す
    [super setSelected:selected animated:animated];
    
    // ラベルのハイライトを設定
    _titleLabel.highlighted = selected;
    _feedLabel.highlighted = selected;
}

UILabelにはhighlightedプロパティがある。
これがYESになると、テキスト色にhighlightedTextColorが使用される。

【おまけ】GUI関係が出てくると気がはやる

テーブルとテーブルセル、このビューレイアウトは、
iPhoneアプリの大半で使われているものです。

このあたりの内容が出てくると、さすがに気がはやります。
現在、「読書と実践」の内で「読書」の部分しか、こなせていません。

「実践」が出来ていないのです。

本の内容に従って実際にRSSReaderを作成しつつ、
記事を書き進めるのがベストなのですが、
Xcode4へのバージョンアップなどもあり、
「実践」が追いついていません。

今は、「早く実際にコーディングしたい」という気持ちと、
「とにかく、ひと通り終わらせてしまいたい」と言う気持ちがせめぎ合い中。 *02あれ?昨日も同じ様なことを言っていた気が…

まあ、あと3章と少し。
何とか、行けるところまで頑張ってみましょうか。


脚注

脚注
01 まあ、名前見れば想像はつく
02 あれ?昨日も同じ様なことを言っていた気が…

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください