はじめに
UIKitを利用する以上、 UITableViewCell
はまだまだ現役と思います。
カスタムセルを作成した際に、初期化処理はとりあえず prepareForReuse
内に書いておけば良いと思っていたのですが、改めてドキュメントを読むとそういうわけでもなさそうなので書き留めておこうと思った次第です。
prepareForReuse()
メソッドのドキュメントを読む
DeepLでそのまま日本語翻訳すると、
UITableViewCellオブジェクトに再利用識別子がある場合、テーブル・ビューはUITableViewメソッドdequeueReusableCell(withIdentifier:)からオブジェクトを返す直前にこのメソッドを呼び出します。潜在的なパフォーマンスの問題を避けるために、セルの属性は、アルファ、編集、選択状態など、コンテンツに関係のないものだけをリセットする必要があります。tableView(_:cellForRowAt:)のテーブルビューのデリゲートは、セルを再利用するとき、常にすべてのコンテンツをリセットする必要があります。
これによると prepareForReuse()
内で初期化すべきものはセル自体の属性に留めることが推奨されています。セル上に配置したコンポーネントなどの初期化は避けた方が良いということです。
セルの初期化の実装例
色々な実装パターンがありそうですが、個人的にはセル自体の属性の初期化は prepareForReuse()
内で、それ以外は tableView(_:cellForRowAt:)内で書くことが多いです。
より適切な書き方とかあればぜひ教えてください🙇
final class CustomCell: UITableViewCell {
private let titleLabel = UILabel()
private let subtitleLabel = UILabel()
override func prepareForReuse() {
super.prepareForReuse()
backgroundColor = .systemBackground
selectionStyle = .none
accessoryType = .none
}
func initContents() {
titleLabel.text = nil
subtitleLabel.text = nil
}
}
上記のように、2つの UILabel
コンポーネントを初期化する場合は、initContents()
のようなinternalなメソッドを用意しておくと、tableView(_:cellForRowAt:)
で呼び出せます。
final class TableViewController: UITableViewController {
// 省略
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomCell
// セルのコンテンツの初期化
cell.initContents()
return cell
}
終わりに
単にドキュメントに従おうという話ですが、prepareForReuse()
内に初期化処理をまとめて書かれていることをよく見るので、これを機に少し書き方を変えても良いかもしれません。 (どれくらいパフォーマンスに影響するかはわかっておらず)
参考文献
この記事は、以下の情報を参考に書きました。