廃墟

本ブログは更新を終了しました。 技術的な記事のみ、有用性を鑑みて残しておきます。

iOSアプリ開発における正しいMVC

この記事は iPhone Advent Calendar 2013 - Adventar の12月24日分の記事になります。

今年もアドベントカレンダーが熱いわけですが、今年は僕は年中iOSアプリのコードを書いていたので、その中で手に入れた or 手に入れつつある様々な知見を皆さんに紹介していきたいと思います。

MVCって何だっけ? 〜UITableViewCellってあれで良いのか?〜

この記事を読んでいる方で、こんなコードを書いている人はいませんか?

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    
    UIImageView *myImageView = (UIImageView *)[cell viewWithTag:10];
    
    myImageView.image = [UIImage imageNamed:self.imageName];
    
    return cell;
}

はい。少し前までの僕です。。
しかし、ここはあえて言わせて頂きたい。 糞コードだ! …と。

そもそもこれって、Viewの分離ができていないわけで、"M"と"VC"でしか分かれてないわけです。 それってPHPSymfony使って書いてるのと変わらない概念なわけで、そんな前時代的な(以下省略

正しいUITableViewCellの扱い方

こんな時、どうすればいいのかっていうと、最低限やりたいのが「Viewの分離」なわけです。Controllerのもつ役割とViewの持つ役割を分離しましょう。

具体的には、こんな感じ。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    AKNGoodTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    
    AKNEntry *entry = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.titleLabel.text = entry.title;
    cell.bodyLabel.text  = entry.body;
    
    return cell;
}

// 途中省略

@interface AKNGoodTableViewCell : UITableViewCell

@property (nonatomic) IBOutlet UILabel *titleLabel;
@property (nonatomic) IBOutlet UILabel *bodyLabel;

@end

@implementation AKNGoodTableViewCell

@end

こんなふうにして、StoryBoardからアウトレットを引っ張ってあげましょう。 ちゃんとAutomatic の所に出てきますよ。

と、ここまで書いたのですが、コードで説明したほうが早いのでコードを書いていたら深夜になったので、一旦この記事を公開してしまいます。
後で説明を追記しようと思うので、良かったら左上、「読者になる」ボタンを押してやって下さい!

AknEp/AKNAdventar · GitHub

その他ありそうな疑問など

これじゃCellを複数のViewControllerで使いまわせないけどどうしたらいいの?

セルに対応したNibファイルを作っておいて、 registerNib:forCellReuseIdentifier: というメソッドを使うと解決します。
但し、UITableViewControllerで直接的に行うのではなく、対応するセルのクラス側にクラスメソッドを容易すると、よりエレガントになりそうです。 (ファイル名を再定義する必要がなくなるので。)

これって普通のViewController でも同じようなことをした方が良いの?

yesです。

特に、複雑な画面では、部分ごとにUIViewのサブクラスを作ってあげると、効果的でしょうね。

フリーランスでやってます。

いろいろ引き受けてます。興味があったら以下のメールアドレスまでどうぞ。 ご相談お待ちしております。

master(at-mark)silph.jp