iOSのUITable Viewの性能を詳細に整理し最適化する


紹介します
iOSの開発において、UITable Viewは、いつも私たちが最も多く付き合うUIコントロールの一つかもしれません。その重要性は言うまでもありません。Androidもこのように、AndroidのListViewとUITTable Viewは同じ機能のコントロールですが、iOSのUITable Viewはもっと強いです。理由は言わないです。Androidを勉強したらiOSのUITTable Viewはとても簡単に使えます。これもAndroidよりiOSが好きな理由の一つです。今日の研究の内容はUITTable Viewの最適化です。
開始前に、いくつかのUITable Viewの最適化されたアイテムを話すことができますか?エクセル多重(AndroidではListViewの重用とよく言われていますが、多重化は同じ意味です。峰哥が以前Androidを作ったことがありますので、時々「重用」と言います。後でもし「重用」と言ったら、「多重化」の意味が分かります。)!セルを除いて再利用しますか? 
二、UITTable Viewの性能最適化
1、セル多重化
多重化は簡単です。これはすべてのiOS開発者が最もよく知っている最適化コンテンツかもしれません。

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
 static NSString *Identifier = @"cell";
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
 if (!cell) {
 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
 }
 
 return cell;
}
しかし、このように重用すれば完璧ですか?
私たちはよく注意しています。cell ForRowAtIndexPath:cellごとにデータをバインディングしています。実際には、cell ForRowAtIndexPathを呼び出した時に、cellはまだ表示されていません。効率を上げるために、データを結合した操作をセルに表示してから実行します。テーブルビュー:willDisplayCell:forRowAtIndexPath:(以后willDisplayCellと略称する)方法でデータをバインドすることができます。
ウィルDisplayCellは、セルがtableviewで展示される前に呼び出します。この時、セルのインスタンスはすでに生成されていますので、セルの構造を変更することはできません。
2、セル高さの計算
こちらは二つのセルに分けられます。一つは定高のセルで、もう一つはダイナミック高さのセルです。
(1)定高のセルは、次のようにするべきです。

self.tableView.rowHeight = 88;
この方法はすべてのセルの高さが88のテーブルビューであることを指定しています。rowHeightのデフォルトの値は44ですので、空いているテーブルビューはこのように表示されます。定高セルに対しては、上記の方法で指定された高さを直接採用して、必要でない計算とオーバーヘッドを節約するために、tableView:height ForRowAtIndexPathを実現する必要はありません。
(2)ダイナミック高さのセル
高度を与えるために、そのエージェントを実装する必要があります。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
 // return xxx
}
このプロキシ方法が実現すると、上のrowHeightの設定は無効になります。この方法では、セルの高さの計算効率を向上させ、時間を節約する必要があります。
iOS 8以降はself-sizing cellという概念があり、セルは自分で高さを算出できます。self-sizing cellを使うには以下の3つの条件を満たす必要があります。
(1)Autolayoutを用いてUIレイアウト制約を行う(cell.com ntViewの4つの辺はいずれも内部要素と制約関係があることが要求される)。
(2)TableViewのestimatited RowHeight属性のデフォルト値を指定します。
(3)Table ViewのrowHeight属性を指定するのはUITTable View Automatic Dimensionです。

- (void)viewDidload {
 self.myTableView.estimatedRowHeight = 44.0;
 self.myTableView.rowHeight = UITableViewAutomaticDimension;
}
セルの高さの計算効率を上げる以外に、すでに計算された高さに対してはキャッシュを行う必要があります。計算された高さに対しては、2回目の計算をする必要はありません。
3、レンダリング
TableViewの流暢さを保証するために、急速に滑る時、セルは速くレンダリングされなければなりません。ですから、セルのレンダリング速度は速くしなければなりません。どうやってセルのレンダリング速度を上げますか?
(1)画像がある場合、先に画像をレンダリングし、bitmap contextでそれを一回描き、UImageオブジェクトに導出してからスクリーンに描画すると、レンダリング速度が大幅に向上します。具体的な内容は、「プレレンダリングによるiOS画像の表示加速」に関する資料を自分で探すことができます。
(2)レンダリングの一番いい時の操作の一つはミックスです。だから、透明な背景を使わないで、セルのopaque値をYesにします。背景色はclear Colorを使わないでください。できるだけ影のグラデーションなどを使わないでください。
(3)ハイブリッド操作はGPUを使って行われるので、CPUでレンダリングできます。このようにミキシング操作は行われません。UIViewのdrawRect方法でカスタマイズできます。
4、ビューの数を減らす
私たちはセルにシステムコントロールを追加する時、実際にシステムは下のインターフェースを呼び出して絵を描きます。コントロールを大量に追加すると、大きな資源を消耗し、レンダリングの性能にも影響します。デフォルトのUITable Viewcellを使用して、そのContentViewの上にコントロールを追加すると、かなりの性能が消耗されます。したがって、現在の最善の方法は、UITable ViewCellを継承し、DRawRect方法を書き換えることです。
5、余計な描画操作を減らす
DRawRect方法を実現する時、そのパラメータrectは私達が描くべき領域であり、rect範囲外の領域では描く必要がありません。そうでないとかなりの資源を消耗します。
6、セルにsubViewを動的に追加しないでください。
セルを初期化する際には、必要なすべてのディスプレイを追加し、必要に応じてhide属性の表示と非表示を設定します。
7、非同期UI、メインスレッドをブロックしないでください。
私達は時々このような現象を見ます。ロードする時、ページ全体が詰まって動かないので、どうやって注文しても無駄です。フリーズしたようです。原因はメインスレッドがブロックされたからです。したがって、ネットワークデータの要求や画像のロードに対しては、マルチスレッドを開いて、時間のかかる操作をサブスレッドに置いて、非同期的に行うことができます。これは各iOS開発者が知っている知識かもしれません。多く言う必要はありません。
8、スライド時に必要に応じて内容をロードする
目標行と現在の行が指定された行数を超えている場合は、目標スクロール範囲の前後に3行のロードのみを指定します。

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset{
 NSIndexPath *ip = [self indexPathForRowAtPoint:CGPointMake(0, targetContentOffset->y)];
 NSIndexPath *cip = [[self indexPathsForVisibleRows] firstObject];
 NSInteger skipCount = 8;
 if (labs(cip.row-ip.row)>skipCount) {
  NSArray *temp = [self indexPathsForRowsInRect:CGRectMake(0, targetContentOffset->y, self.width, self.height)];
  NSMutableArray *arr = [NSMutableArray arrayWithArray:temp];
  if (velocity.y<0) {
   NSIndexPath *indexPath = [temp lastObject];
   if (indexPath.row+33) {
    [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-3 inSection:0]];
    [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-2 inSection:0]];
    [arr addObject:[NSIndexPath indexPathForRow:indexPath.row-1 inSection:0]];
   }
  }
  [needLoadArr addObjectsFromArray:arr];
 }
}
テーブルビュー:cell ForRowAtIndexPath:メソッドに判定を入れることを覚えています。

if (needLoadArr.count>0&&[needLoadArr indexOfObject:indexPath]==NSNotFound) {
 [cell clear];
 return;
}
スライドが速い場合は、ターゲット範囲内のセルのみをロードし、必要に応じてロードします。
締め括りをつける
以上はこの文章の全部の内容です。本文の内容は皆さんの学習や仕事に一定の助けをもたらすことを望んでいます。もし疑問があれば、メッセージを残して交流してください。ありがとうございます。