The other day I was developing a dictionary view controller that consisted of a UITableView and an NSArray (approx. 4000 elements) holding the data to be shown. As the elements were of varying lengths I had implemented the delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
to dynamically calculate the size that the cell should be based upon its content. However I was seeing a significant delay (at least 5 seconds) on loading the tableview, thinking it was because of my dataset taking to long to load, I attempted varies NSOperation solutions to overcome this. None of the solutions succeed in greatly speeding up the loading time so I decided to include NSLog statements into my methods to see if one method was being worked more than I thought it was.
It turns out that the heightForRowAtIndexPath method gets called for every row in your tableview when the tableview's data is loaded into it not just before it displays the row/cell as I had thought. In the documentation Apple have provided the following warning:
"There are performance implications to using tableView:heightForRowAtIndexPath: instead of the rowHeight property. Every time a table view is displayed, it calls tableView:heightForRowAtIndexPath: on the delegate for each of its rows, which can result in a significant performance problem with table views having a large number of rows (approximately 1000 or more)."
I had a dilemma do I break down my data set into smaller chunks so that each chunk is under the 1000 rows limit or have each cell be the same height (using the rowHeight property).
In the end I decided to go with the rowHeight property solution (the same data structure was being used in multiple other locations in my app resulting in a lot of extra work to alter its structure or maintain two datasets). Happily enough as it turned out that very few of the data elements were as different in length as I had thought (for those that were I just decreased their font size).