iOS のアプリ開発における主役クラスの1つである UIViewController。中でも、実用系のアプリを作る際には UITableView を表示するための UITableViewController が活躍してくれます。Xcode の新規クラスのテンプレートにも含まれていますね。
UITableViewController は UIViewController のサブクラスで、UITableViewDataSource と UITableViewDelegate という、UITableView を扱うのに必要な2つのプロトコルに適合しています。UITableView を表示する画面なら、基本的に UITableViewController クラスだけで事足りてしまいます。
とても便利なクラスである反面、複雑な処理をしようとすると、どんどん肥大化してしまうという欠点もあります。原因の1つとして、UITableViewController が次の3つのクラス/プロトコルの役割を1クラスで担っている点が考えられます。
- UIViewController
- UITableViewDataSource
- UITableViewDelegate
肥大化した UITableViewController にあるたくさんのフィールドやメソッドは、それぞれが上記3つのうちどの役割のために必要なものなのか、だんだんわかりにくくなってきてしまいます。
また、実装を共有したい場合にも、1つのクラスにすべて収まっていると何かと都合の悪い点が出てきたりもします。
そこで、あくまでケース・バイ・ケースではありますが、あえて UITableViewController を使わず、UIViewController のサブクラスと、それとは別に作った UITavieViewDataSource と UITableViewDelegate を組み合わせて使うということをよくやるようになりました。実際には、3つをすべて分離するのではなく、UITableViewDataSource と UITableViewDelegate に適合したクラスを作って、UIViewController から UITableView 関連の処理を分離したような実装にするパターンを何度か使っています。
このように役割を分担することで、個々のクラスはよりシンプルになります。さらに、たとえば検索用の UISearchDisplayController の UITableView の dataSource/delegate を、メイン UITableView の dataSource/delegate と同じクラスをもとにした別のインスタンスにして、どちらの UITableView 用の処理かの判別を不要にする、というような設計も可能になります。
1つ注意しておかなくてはいけないのは、UITableViewController は、単に UITableViewDataSource と UITableViewDelegate に適合した UIViewController というだけではないという点です。詳しくは API ドキュメントにありますが、たとえば次のような機能を持っています。
- 初回の画面表示時にセルのリロードと選択のクリア処理が入る。
- 画面表示後に、スクロールバーを点滅させる。
- setEditing:animated: 時に、UITableView の編集状態を連動させる。
UITableViewController を使わない場合、必要に応じてこれらの機能を自分で実装する必要があります(簡単です)。単に UITableViewDataSource とUITableViewDelegate を分離してみたら思った通りに動かない場合はそのあたりを確認してみてください。
このように分離した設計で1つ悩みどころが、UITableViewDataSource と UITableViewDelegate の2つに適合したクラスの一般的な呼び方です。なかなか良いものが思いつかず、何とかひねり出したクラス名をつけていますが、今もこの文章を書きながら「いい名前ないかなぁ」と考えてしまっています。