12

I have a UITableview that lazy loads images of all different sizes. When an image loads, I need to update the specific cell, so I figured out I need to use reloadRowsAtIndexPaths. But when I use this method, it still calls the heightForRowAtIndexPath method for every single cell. I thought the whole purpose of reloadRowsAtIndexPaths is that it will only call heightForRowAtIndexPath for the specific row you specify?

Any idea why?

[self.messageTableView beginUpdates];
[self.messageTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:count inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
[self.messageTableView endUpdates];

Thank You

Jesse
  • 2,674
  • 6
  • 30
  • 47
  • have you tried using only.. [self.messageTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:count inSection:0]] withRowAnimation:UITableViewRowAnimationNone]; – Ashish P. Oct 25 '13 at 17:58
  • You mean instead of wrapping it in beginUpdates and endUpdates? Yes I tried that and it still tries to redo the height for every single cell. Really annoying as I am expecting it to call heightForRowAtIndexPath just for this particular cell. – Jesse Oct 25 '13 at 18:07
  • Am I right in believing that it should only call heightForRowAtIndexPath for this one cell? Or does it call this method again for every cell in the table? – Jesse Oct 25 '13 at 18:48
  • I think it should call for only row that you are reloading. I dont know why it is calling for all visible rows. It may depends on how you displaying your cell. Try without dequeueReusableCellWithIdentifier. – Ashish P. Oct 25 '13 at 19:01
  • How do you create the cell without dequeueReusableCellWithIdentifier? So what I have determined is that the only difference between reloadData and reloadRowsAtIndexPaths in my app is that reloadData calls cellForRowIndex for each visible cell, whereas reloadRowsAtIndexPaths calls cellForRowIndex just for the one cell. But they still both call heightForRowAtIndexPath for every single cell in the table uggh – Jesse Oct 25 '13 at 19:06
  • Try this code cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CellIdentifier"]; it will initiate new cell object for each row without reusing visible rows. – Ashish P. Oct 25 '13 at 19:12
  • tried that and my tableview just comes up empty. My cells have custom classes, not sure if that is why, but it just doesnt load anything in the UI when I do it this way... – Jesse Oct 25 '13 at 19:14

1 Answers1

7

endUpdates triggers a content size recalculation, which requires heightForRowAtIndexPath. That's just how it works.

If it's a problem, you could pull your cell configuration logic outside of cellForRowAtIndexPath and reconfigure the cell directly without going through reloadRowsAtIndexPaths. Here is a basic outline for what this could look like:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellId = ...;
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
    }
    [self tableView:tableView configureCell:cell atIndexPath:indexPath];
    return cell;
}

- (void)tableView:(UITableView *)tableView configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    //cell configuration logic here
}

Then, wherever you're currently calling reloadRowsAtIndexPaths, you do this instead and heightForRowAtIndexPath won't be called:

UITableViewCell *cell = [self.messageTableView cellForRowAtIndexPath:indexPath];
[self tableView:self.messageTableView configureCell:cell atIndexPath:indexPath];
Timothy Moose
  • 9,895
  • 3
  • 33
  • 44
  • 1
    The problem is not cellForRowAtIndexPath. It is the fact that heightForRowAtIndexPath is called for every single cell in the UITableView when I do any type of reload. I stopped using beginUpdates and endUpdates, but this still happens – Jesse Oct 29 '13 at 14:46
  • @Jesse You may have missed my point. If you move your cell's configuration logic out of `cellForRowAtIndexPath` into a standalone method (which you would call from `cellForRowAtIndexPath`, you can update the cell's configuration by calling the method directly instead of using `reloadRowsAtIndexPaths` (which indirectly calls `cellForRowAtIndexPath`) thereby bypassing the table view's reload behavior that involves recalculating the content size (which indirectly calls `heightForRowAtIndexPath`). – Timothy Moose Oct 29 '13 at 16:05
  • Hey Tim. I called configure cell method but I got autolayout constraint conflict, it says my cell height is 300 whereas my picture height is greater than 300. It seems calling configure cell doesn't update the height of the cell. Is there anyway to inform table view to update the height? I tried to manually call the heightForRow method right before calling configure cell again. – Zhang Oct 14 '14 at 12:17
  • @Zhang you'll need to reload the rows in order to have the table view update their heights. – Timothy Moose Oct 14 '14 at 15:45
  • but if I call reloadRowsAtIndexPath it'll crash the app, as mentioned above question? – Zhang Oct 15 '14 at 01:40
  • Perhaps the best solution is the server returns the width and height for each picture in the cell. Web developers logic is the reverse of iOS, they give the browser the content and the browser automagically resize the cell to the height of its content whereas iOS requires developer to provide the height before it generates the content =/ – Zhang Oct 15 '14 at 02:18
  • @Zhang I don't see where a crash is mentioned. However, there are solutions for auto-sized cells. iOS8 supports auto-sized cells by setting the table view's row height property to: `tableView.rowHeight = UITableViewAutomaticDimension`. In iOS7 and below, there are techniques such as [discussed here](http://stackoverflow.com/questions/13660004/retrieve-custom-prototype-cell-height-from-storyboard). If you're getting a crash, consider posting a new question with detail. Its difficult to discuss in comments. – Timothy Moose Oct 15 '14 at 17:35
  • Why not just call reloadRowsAtIndexPaths without begin/end updates? I see in the documentation begin/end updates is necessary only for "insertions, deletion, and selection operations", this isn't any of those. – User Mar 23 '15 at 13:46
  • @Ixx that recalculates height too (see question's comment thread) – Timothy Moose Mar 23 '15 at 20:51