UITableViewを使ったときの諸々

iOSアプリを幾つか作成してきましたが、、ゲーム系が多かったため始めてまじめにUITableViewを使いました。
諸々調べつつ作ったのですが、すぐ忘れると思うのでまとめ。

1. UITableViewを使う場合にUITableViewControllerを使わない方法

ViewとControllerを明示的に分けたい場合の方法

[view.h]
@interface hogeView : UIView <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, weak) UITableView *hogeTable;

[view.m]
- (void)layoutSubviews
{
    UITableView *tbl = [[UITableView alloc] initWithFrame:self.bounds style:UITableViewStylePlain];
    tbl.delegate = self;
    tbl.dataSource = self;
    [self addSubview:tbl];
    self.hogeTable = tbl;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return @"";
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cell"];
    }
    return cell;
}

・UITableViewDelegateと、UITableViewDataSourceの2インターフェースを実装したクラスが必要。
・2つのインターフェースはUITableView構築時に”いくつセルがあるか?”や、”セルの中身は?”に随時答えるクラス。とりあえず、上のメソッドを追加しておけば何も表示されないがコンパイルは可能。
・2つのインターフェースは別にViewに実装する必要はない。

2. UITableViewを使う場合に引っ張って更新をする方法

こちらiOS6以降については、UIRefreshControlをUITableViewにaddしておくことで、引っ張られたイベントが通知されるようになります。

[view.h]
    :
@property (nonatomic, weak) UIRefreshControl *refreshControl;

[view.m]
- (void)layoutSubviews
{
    :
    :
    :

    UIRefreshControl *rc = [[UIRefreshControl alloc]init];
    [rc addTarget:self action:@selector(onRefresh:) forControlEvents:UIControlEventValueChanged];
    [tbl addSubview:rc];
    self.refreshControl = rc;
}

- (void)onRefresh:(id)sender
{
    [self.refreshControl beginRefreshing]; // UITableViewの上部でローディングが回るようになる

    // 非同期データ更新
    :
}

- (void)didRefresh
{
    // 非同期データ更新後
    [self.refreshControl endRefreshing]; // UITableViewの上部でローディングが止まって消える
}

・イベント通知に合わせて、beginRefreshing/endRefreshingを呼び出すことでローディングを表示してくれる優れた方
・忘れると戻らないので、通信エラー等の場合もendRefreshingを忘れないように。
・ローディング時にあわせて表示するテキストも設定可能

3.非同期通信でcellのimageを更新する方法

cellのテキスト部分だけ先に表示して、imageは取得毎に表示という方法
※通信にはAFImageRequestOperationを利用する方法のため、事前にAFNetworkingを組み込んでおく必要あり
※AFNetworkingはpodもしくは、zipでダウンロードしたファイルをプロジェクトに組み込んでも問題なし

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    :
    :
    NSURL *url = @"http://xxxxxxxxxxxxx/xxx.png"; // 画像URL
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFImageRequestOperation *operation =
    [AFImageRequestOperation imageRequestOperationWithRequest:request
                                                          success:^(UIImage *image) {
                                                              cell.imageView.image = image;
                                                              [cell setNeedsLayout];
                                                          }];
    [operation start];
}

・取得後にsetNeedsLayoutをすることでcellのレイアウトが再調整される(これがないと、画像が表示されない)
・error時にはエラー用のicon等をプロジェクトから読み出して表示する、、ほうがユーザには解りやすいと思う。

4.Cell間の線を非表示にする方法

デザインが指定されていて、UITableViewのデフォルトの灰色の線を消したいとき

    UITableView *tbl = [[UITableView alloc] initWithFrame:self.bounds style:UITableViewStylePlain];
    tbl.separatorColor = [UIColor clearColor];