For static (non-data-driven) height, you can just dequeue the cell once and store the height:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSNumber *height;
if (!height) {
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];
height = @(cell.bounds.size.height);
}
return [height floatValue];
}
For dynamic (data-driven) height, you can store a prototype cell in the view controller and add a method to the cell’s class that calculates the height, taking into account the default content of the prototype instance, such as subview placement, fonts, etc.:
- (MyCustomCell *)prototypeCell
{
if (!_prototypeCell) {
_prototypeCell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCustomCell"];
}
return _prototypeCell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Data for the cell, e.g. text for label
id myData = [self myDataForIndexPath:indexPath];
// Prototype knows how to calculate its height for the given data
return [self.prototypeCell myHeightForData:myData];
}
Of course, if you’re using custom height, you probably have multiple cell prototypes, so you’d store them in a dictionary or something.
As far as I can tell, the table view doesn’t attempt to reuse the prototype, presumably because it was dequeued outside of cellForRowAtIndexPath:
. This approach has worked very well for us because it allows the designer to modify cells layouts in the storyboard without requiring any code changes.
Edit: clarified the meaning of sample code and added an example for the case of static height.