Morizotter Blogでも、UITableViewのことを書いた記事(NibからCellを作って使いまわしてUITableViewCellを楽々カスタマイズ!)が結構人気があるので、今回はUITableViewのセルの使い回しについて書いてみようと思います。
- 参考コードにはUIStoryboardでの簡単なカスタムセルの作り方も紹介しているので興味のある方は是非、見てみてください。
UITableViewの扱いなんて結構基本的なところですが、誰もが通るハマりということで興味を持っていただける方もいるのではないかなと。ただ、詳細はサンプルコードを見ていただくこととして、考え方などを書いていこうと思います。
UITableViewはセルの使い回しを考慮した構造になっている
僕が始めたてから数ヶ月の間理解できなかったポイントとして、「セルの使い回し」というUITableViewの構造がありました。画面の上にViewをたくさん置いてしまうと、アプリがどうしても重くなってしまうので、セルは画面の外に出たら一旦画面から外されて、そのまま使いまわされます。その処理を勝手にやってくれるのですが、その部分がブラックボックスになっていて、最初のうちは結構苦しむポイントだと思います。
画面に表示されているセルの個数が5個ならUITableViewは6個か7個くらいしかセルを作らず、その6個か7個を使いまわしています。
まずは使い回しの基本を理解する
使い回しの基本を理解するには、UIStoryboardのメソッドを書く前に、オーソドックスなメソッドを見るのが一番だと思います。これですね。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"CellIdentifier"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; } return cell; }
これにははじめの頃悩まされました。。。。。。。。 staticって何とか、dequeueって何とか、cell==nil
がなぜ書かれているのとか,,,CellIdentifierって何の意味があるの,,,とか、意味不明なことがたくさんありました。ただ、これ、ちゃんとわかるとUITableViewの凄さがわかるし、自分で設計する際にも役立つことが盛り沢山なんですね。ちょっと丁寧に解説してみます。説明は、セルの使い回しに関係する重要なところと、それ以外のところにわけます。
重要な所としては、まず、dequeueReusableCellWithIdentifier:
です。tableViewのこのメソッドを送ると、CellIdentifierという印がついたセル(同じ種類のセル)で使い回しができるものがあればそれを返してくれます。それが、左側のUITableViewCell *cell
のところに入ってきます。テーブルが表示された直後など、使い回しできるセルがない場合は、nilが返って来ます。この場合、cellはnilとなるわけです。
そこで、次のif文が大切な役割をします。if文ではcellがnilだった場合にのみ新しいUITableViewCellを作成するということを行います。その際に、種類を示すCellIdentifierを設定します。再利用可能なセルがある場合はそれを、ない場合は、新しく作成してreturn
で返すんですね。返すと言ってもこれは、UITableViewに渡すことになります。セルを受け取ったテーブルビューはそれを画面上に表示される次のセルとして表示するのです。画面上に表示されるセルの数が5個ならば、新しいセルを作成するのは6回か7回のみです。後は、再利用可能なセルがもう揃っているので呼ばれることはなくなります。
このような形でセルを再利用していくことになります。
それ以外の点ですが、staticについてですが、CellIdentifierは文字列です。staticをつけておけば同じクラス内で文字列を何度も作る必要がなくなります。これはつけなくても問題無いです。CellIdentifierが大文字から始まるのは、中身の文字列は変更されることはないというので、通常の小文字から始まる変数とは区別していると思ってください。
UIStoryboardでセルを作成する
基本がだいたいわかったところで、UIStoryboardで作成したセルの使い回しについてです。UIStoryboard上でセルを作ると本当に簡単に、カスタムのセルができますね。わざわざXibファイルでセルを作る必要もないですし、ガリガリ座標指定して書く必要もありません。理解しておいたほうが良いポイントとしては2つあります。
- UIStoryboardでセルを作成した場合、UITableViewの上にセルを置くことになる。この時点でUITableViewはセルのことを知っている
- カスタムで作成する場合、もちろんUITableViewCellを継承したカスタムのクラスが必要になる
上記のコードと同じ部分を見比べてみます。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ChristmasCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ChristmasCell" forIndexPath:indexPath]; return cell; }
今回はChristmasCellというものにしました。
記述が本当に短くなっていますね。Xcodeのプロジェクトを見ていただけるとわかりますが、セルのidentifierはUIStoryboard上でIdを指定しています。どうして、cell==nil
の判定がいらないのか、それは、tableViewが既に指定されたidentifier(今回はChristmasCell)のことを知っているからです。今回の、dequeueReusableCellWithIdentifier:forIndexPath:
メソッドでは、nilは返りません。必ず出来上がったセルが返って来ます。もし、dequeue..メソッドを実行した時に指定されたセルがない場合、テーブルビューがそのセルを作成して(インスタンス化して)返すからです。一定数のインスタンスができれば後はそれを使いまわすことに変わりはありません。
ということで、セルの使い回し方法がわかりました。詳細は添付のコードを見てみてください><
何かご意見があればなんなりと〜。