【swift】uitableviewが重いときに対処すべき2つのこと

はじめに

今回やりたかったのは、twitterのタイムラインみたいな無限スクロールを軽くしたいということ。

今までも重いのは知ってたんだけど放置してきましたが、いよいよ開発も終盤にさしかかってきてパフォーマンスやら細かい部分も修正しないとならなくなってきました。

正直、対応できるのかなと思っていたのですが、なんとかなりそうなのでメモしておきます。

やるべきこと

1.セルの高さをキャッシュすること
2.セルの高さ計算のためのセルクラスを使い回すこと
3. セルに画像があるならキャッシュすること

2つって書いたけど、3つありました。けど3つ目のはもともとやっていたのでのぞきました。
1、2は今回、実際に対応してみたホント劇的に改善したので知らない方は試してみてください

実装例

セルの高さをキャッシュする

細かくはまだ調べてないんですけど、heightForRowAtIndexPathって頻繁に呼ばれるいる印象です。
基本的に1度計算すればokなはずなので何度も同じ処理をしないようにしたら速くなりました。

遅い例

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
    var cell = UITableViewCell()
    return cell.calcHeight() // 高さを毎回計算する
}

速い例

var cacheHeight = [CGFloat] = [CGFloat]()
・・・
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
    if self.cacheHeight.count <= indexPath.row
    {
        // キャッシュ(未計算)がない場合
        var cell = UITableViewCell()
        var height = cell.calcHeight()
        self.cacheHeight.insert(height, atIndex: height);
        return height
    }
    else
    {
        // キャッシュ(計算済み)の場合
        return self.cacheHeight[indexPath.row]
    }
}
セルの高さ計算用のクラスを別途準備する

高さを計算するだけなのになんどもセルクラスを生成してました。
思っている以上にnewするコストって高くて、、、newは1回すればokということを理解しました

遅い例

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
    var cell = UITableViewCell()
    return cell.calcHeight() // UITableViewCellクラスを幾つも生成している
}

速い例

var cell = UITableViewCell()
・・・
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
    if self.cacheHeight.count <= indexPath.row
    {
        return cell.calcHeight() as! CGFloat // 高さを求めるだけなので毎回newとかしないで使い回せばよい
    }
}
テーブルセルに画像があるならキャッシュする

これはみんなやってるかと思いますが、SDWebImageとかいうのが鉄板ぽいので、画像を表示する必要があればこれを必ずつかいます

さいごに

しっていればなんてことないんですけど、実際にやってみると想像していたらよりかなり速くなりました。
こんなに簡単にサクサク動くようになるなんてと思うこと間違いなしなのでみなさん是非お試しください

以上です