UITableView が作成され、reloadData メッセージを送信するたびに、セルごとに 1 つの heightForRowAtIndexPath メッセージがデータソースに送信されます。したがって、テーブルに 30 個のセルがある場合、そのメッセージは 30 回送信されます。
これらの 30 個のセルのうち 6 個だけが画面に表示されているとします。その場合、作成時に reloadData メッセージを送信すると、UITableView は表示される行ごとに 1 つの cellForRowAtIndexPath メッセージを送信します。つまり、そのメッセージは 6 回送信されます。
なぜAppleはこのように実装するのですか? その理由の 1 つは、ほとんどの場合、セル全体を構築してデータを入力するよりも、行の高さを計算する方が安価だからです。また、多くのテーブルですべてのセルの高さが同じであることを考えると、多くの場合、はるかに安価です。その理由の一部は、iOS がテーブル全体のサイズを知る必要があるためです。これにより、スクロール バーを作成し、スクロール ビューなどに設定することができます。
テキストの量が異なるために行の高さが異なる場合は、関連する文字列に対していずれかの sizeWithFont: メソッドを使用して計算を行うことができます。これは、ビューを構築してから結果を測定するよりも高速です。セルの高さを変更する場合は、テーブル全体をリロードする必要があることに注意してください (reloadData を使用 - これはデリゲートにすべての高さを要求しますが、表示されるセルのみを要求します)、またはサイズが指定されている行を選択的にリロードする必要があります。かわった。
追加資料
コメントのフォローアップの質問を理解できれば、以下が役立つ場合があります。
編集モードを実装している場合、テーブルの行の高さを変更する必要があることは珍しくありません。たとえば、表の行にテキストがあり、セルの幅が狭くなった場合 (右側の削除円のためのスペースを確保するため)、テキストを収めるために一部のセルの高さを高くしたい場合があります。ここでの基本的なアプローチは次のとおりです。
tableView:heightForRowAtIndexPath: メソッドが、編集モードかどうかを認識していることを確認してください。(isEditing を使用して tableView に問い合わせることができます。)次に、編集モードかどうかに応じて、正しい高さを返すメソッドを取得します。
setEditing:animated: UITableViewController (または UIViewController のどちらを使用していても - 使用するものに応じていくつかの違いがあるため、ドキュメントを注意深く確認する価値があります) の setEditing:animated: メソッドで、状態を変更した後に tableView に reloadData メッセージを送信します。 . これにより、tableView はすべての行の高さを取得し、表示されている行のセルを再フェッチします。tableView は、編集モードに入ったときにセルを狭くする処理を行いますが、レイアウトでさらに作業を行いたい場合は、tableView:cellForRowAtIndex: で行います。前述のように、一般的な戦略は、高さをすばやく計算する方法を見つけることです。テキスト sizeWithFont: (およびそのバリアント) を使用すると、それを行うことができます。画像などがある場合は、それらの寸法を取得して合計することができます。
これらの手順に加えて、モードを切り替えた後に tableView を少しスクロールすることもできます。行の高さが異なる場合、モードを切り替えた後、テーブル内の間違った位置になります。ここで取ったアプローチは、テーブルをリロードした後に performSelector:withObject:afterDelay を使用して、スクロール調整を行うメソッドを呼び出すことです。tableView が新しい高さと新しいテーブル セルを収集する時間を確保するために、遅延を使用する必要があります。(これを行うよりスマートな方法があるかもしれません。) リロードの前後で画面に最初に表示されるセルの tableView:cellForRowAtIndexPath: の origin.y の差に基づいてスクロール調整を行うために、いくつかの合計を行います。たとえば、プリロード前の位置を取得するには、次のようにします。
CGPoint offset = [[self tableView] contentOffset];
NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:CGPointMake(0,offset.y)];
CGFloat preCellOffset = [[[self tableView] cellForRowAtIndexPath:indexPath] origin].y;