The way Apple implements UITableView is not intuitive to everyone and it’s easy to misunderstand the role of
heightForRowAtIndexPath:. The general intention is that this is a faster and light-on-memory method that can be called for every row in the table quite frequently. This contrasts with
cellForRowAtIndexPath: which is often slower and more memory intensive, but is only called for the rows that are actually need to be displayed at any given time.
Why do Apple implement it like this? Part of the reason is that it’s almost always cheaper (or can be cheaper if you code it right) to calculate the height of a row than it is to build and populate a whole cell. Given that in many tables the height of every cell will be identical, it is often vastly cheaper. And another part of the reason is because iOS needs to know the size of the whole table: this allows it to create the scroll bars and set it up on a scroll view etc.
So, unless every cell height is the same, then when a UITableView is created and whenever you send it a reloadData message, the datasource is sent one heightForRowAtIndexPath message for each cell. So if your table has 30 cells, that message gets sent 30 times. Say only six of those 30 cells are visible on screen. In that case, when created and when you send it a reloadData message, the UITableView will send one cellForRowAtIndexPath message per visible row, i.e. that message gets sent six times.
Some people are sometimes puzzled about how to calculate a cell height without creating the views themselves. But usually this is easy to do.
For example, if your row heights vary in size because they hold varying amounts of text, you can use one of the
sizeWithFont: methods on the relevant string to do the calculations. This is quicker than building a view and then measuring the result. Note, that if you change the height of a cell, you will need to either reload the whole table (with reloadData – this will ask the delegate for every height, but only ask for visible cells) OR selectively reload the rows where the size has changed (which, last time I checked, also calls
heightForRowAtIndexPath: on ever row but also does some scrolling work for good measure).
See this question and perhaps also this one.