19 | 11月 | 2014 | HMDT Blog

カテゴリー : 2014年 11月19日

『たのスイ』への質問の答え


『たのスイ』の方、色々と質問もいただいています。初心者向けを謳っている本なので、丁寧な説明をこころがけはしました。ですが、iOSは2.0から連綿とアップデートを続けていて、プログラミングのスタイルが変わったり、歴史的な経緯があるものもあります。そういったものをこの本で説明してもしょうがないよな、という気もします。でも気になるっちゃ、気になりますよね。

そんな質問が来たので、ここでも紹介です。

質問:P177(5-2 Playgroundでテーブルを使ってみよう!)で、テーブルビューへのセルのregisterClassを実行しなくとも、なぜセルが表示されるのでしょうか?

答え:テーブルビューを使うときに、もし何の工夫もしなければ、セルは行の数だけ必要になります。ですが、もしテーブルに1000行あったときに、セルのインスタンスを1000個作るとしたら、メモリが無駄になります。そこで、画面に表示されるだけのセルのインスタンスを作り(10個程度)、それ以降はスクロールするたびに前に作ったセルを再利用します。

そのために、セルであるUITableViewCellの初期化を行うときに、init(style, reuseIdentifier)というメソッドを使います。第二引数に、再利用のための識別子を指定します。一度作ったセルを再利用するには、テーブルであるUITableViewのdequeueReusableCellWithIdentifier(identifier)を使って、セルを取得します。

これらを使うと、テーブルビューのデータソースメソッドでセルを作るときは、クラシカルなやり方ではこうなります。

var cell: AnyObject? = tableView.dequeueReusableCellWithIdentifier("cell")
if cell == nil {
    cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
}

iOS 2.0ではこんな感じでした。が、その後、セルの内部に配置するビューをxibファイルを使ってグラフィカルにデザインしたい、という要求が出てきます。また、UICollectionViewというクラスも登場し、データソースのあり方をそちらに合わせたいという思惑もあったのでしょう。テーブルビューにxibファイルを登録して、それをもとにテーブルビュー側にインスタンスの作成から管理させるという発想が出てきます。そのために追加されたのが、registerNib(nib, forCellReuseIdentifier)です(iOS 5から)。さらに、クラスを指定するだけで使えるようにしたのが、registerClass(cellClass, forCellReuseIdentifier)です(iOS 6から)。

なので、iOS 8時代のプログラミングでは「テーブルビューにセルクラスを登録し、セルインスタンスをテーブルビューから取得する」という手法になります。

UITableViewCellにはいくつかのスタイルがあり、それによってはdetailTextLabelを使うことができます。ですが、スタイルはセルの初期化時に指定するので、セルクラスを登録するやり方では、それが使えません。そのためdetailTextLabelを使いたいときは、クラシカルな、セルのインスタンスをプログラム側で作成する、という手法を取ることになります。

もっとも、実際にアプリの開発を進めていくと、UITableViewCellをそのまま使うということはほとんどなく、カスタムプロトタイプを使ったりサブクラスを作ったりすることになります。なので、ここで歴史的な経緯を一生懸命紹介してもしょうがないなぁ、という気持ちもあります。しょせん、遊んでいるだけだし。

ということで書籍では、上記の説明を「テーブルに登録したクラスから作るんじゃなくて、データソースメソッドの中で自前でセルを作って初期化しよう。」という一文に収めました。