Anders
Anders

Reputation: 2941

iOS - my heightForRowAtIndexPath implementation causes performance issues, why?

I use a table view where I override heightForRowAtIndexPath. When I run the Xcode profiler I found the following:

enter image description here

I want to calculate the height based one object's property. I use the same table view for two kind of objects, User and Post. My implementation currently looks like this:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *text;
    Post *cellPost;
    User *cellUser;
    if (_pageType == FOLLOWERS || _pageType == FOLLOWING) {
        cellUser = [self.users objectAtIndex:indexPath.row];
        text = cellUser.userDescription.text;
        if (text == nil) {
            return 70;
        }
    } else {
        cellPost = [self.fetchedResultsController objectAtIndexPath:indexPath];
        text = cellPost.text;
    }

    CGSize boundingSize = CGSizeMake(245, CGFLOAT_MAX);
    CGSize requiredSize = [text sizeWithFont:[UIFont fontWithName:@"TisaMobiPro" size:15]
                               constrainedToSize:boundingSize
                                   lineBreakMode:NSLineBreakByWordWrapping];
    CGFloat textHeight = requiredSize.height;
    CGFloat cellHeight = textHeight + 40;
    if ([cellPost.text isEqualToString:self.post.text]) {
        cellHeight += 44;
        if (cellHeight < 114) {
            cellHeight = 114;
        }
    } else {
        if (cellHeight < 70) {
            cellHeight = 70;
        }
    }

    if (cellPost.repostedBy != nil && cellPost.youReposted.boolValue == NO && _pageType != CONVERSATION) {
        cellHeight += 27;
    }

    return cellHeight;

}

If I remove most of the code and only have, e.g. return 100 the tableView's scrolling performance is much improved. Can you spot or give suggestions on something in my implantation that could cause this performance issue?

Upvotes: 0

Views: 637

Answers (2)

zaph
zaph

Reputation: 112855

If you are targeting iOS7 you can use the NSTableView property: estimatedRowHeight.

From the Apple docs:

Providing a nonnegative estimate of the height of rows can improve the performance of loading the table view. If the table contains variable height rows, it might be expensive to calculate all their heights when the table loads. Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.

Also:

Every time a table view is displayed, it calls tableView:heightForRowAtIndexPath: on the delegate for each of its rows

If you have to use tableView:heightForRowAtIndexPath: cache the heights as @Waine suggests.

Upvotes: 1

Andrea
Andrea

Reputation: 26383


Heights are calculated before the – tableView:cellForRowAtIndexPath: is called and for all the number of cells.
If you are deploying on iOS7 you can use the - tableView:estimatedHeightForRowAtIndexPath:, using that method you can defer this calculation while scrolling the tableview. That means that the method tableView:heightForRowAtIndexPath: is called basically when a cell is displayed. The estimation could be a fixed number close to the average of your TVC or based on some math faster than the one that you implemented.
Thanks to the estimation the TV can set its content size an scroll bar height and doesn't need to calculate each height for 100 of rows in one shot. The payback could be a lag during scrolling because the TV is calculating the actual row height.

Upvotes: 1

Related Questions