-1

I am not a full-time iOS dev and I'm trying to return the cell at the current indexPath but this is crashing and I am not sure exactly why. I maintain the height dynamically on the cell. My cell is a custom UITableViewCell called MICell and I have a property called height which is dynamically calculated in the updateCell method.

#import "MICell.h"

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  MICell *cell = (MICell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
  // hardcoded to 200.0f but still crashing
  NSLog(@"here is my height; %f",cell.height);
  return 200.0f;
}

Edit 1

As a workaround, I am able to make an instance variable and just write the current cell height which is then accessed in heightForRowAtIndexPath, like the following. I do feel that this is potentially making assumptions that I'm not fully comfortable with:

@interface ListViewController (){
  NSMutableArray *_data;
  CGFloat _currentCellHeight;

}

...

-(MICell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{
  static NSString *CellIdentifier = @"MICell";
  MICell *cell = [tableView
                            dequeueReusableCellWithIdentifier:CellIdentifier
                            forIndexPath:indexPath];

  // Configure the cell here ...
  NSDictionary *tmp=[_data objectAtIndex:indexPath.row];
  [cell updateCell:tmp];
  _currentCellHeight=cell.height;
  return cell;
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  return _currentCellHeight;
}

Edit 2

Here's a reference to this exact technique. How to get the cell object in tableView:(UITableView *)tableView heightForRowAtIndexPath function?

Edit #3

The above code works fine - there was an issue with IB connections.

halfer
  • 19,824
  • 17
  • 99
  • 186
timpone
  • 19,235
  • 36
  • 121
  • 211
  • 2
    Which line does it crash on? Does it still log something? Any error message? – Thilo Oct 07 '14 at 02:04
  • unfortunately no error message - wsa thinking just a syntax issue. I'm going to update with an edit that is a workaround and seems to work. Would be interested in knowing if there's a non=workaround sol'n though – timpone Oct 07 '14 at 02:06
  • See [this thread](http://stackoverflow.com/q/8100054/581994) for some ideas on how to get a proper exception message and stack trace. – Hot Licks Oct 07 '14 at 02:18
  • 'heightForRowAtIndexPath' is called for ever cell in your table view BEFORE anything else (unless you also implement 'estimatedHeightForRowAtIndexPath:'). So in this case Edit 1 will not do what you want. Set a break point, is _data initialized? That would be my best guess. – ansible Oct 07 '14 at 02:51
  • data is def initialized - I agree that edit #1 is ugly but does work correctly without estimatedHeightForRowAtIndexPath. – timpone Oct 07 '14 at 03:02
  • so the above works fine - there was IB issue. – timpone Oct 07 '14 at 04:48

2 Answers2

6

It's because you're causing an infinite cycle. You cannot call:

[self tableView:tableView cellForRowAtIndexPath:indexPath];

In height for row at index path.

[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

will cause issues when called from height for row at index path. You must call tableView dequeueReusableCellWithIdentifier: without the forIndexPath. You should probably create a configureWithCell:(YourCellClass *)cell method separate from these so you can just configure your cell after properly dequeueing/allocating it.

Also, you do not grab the height from the cell as you're doing above (unless you're assigning a height property with some weird forwarding stuff that breaks class containment... which you shouldn't do either). Use the following for dynamic cell heights via auto layout: CGFloat cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

Something like the following below should do the trick:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    MyCellClass *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MyCellClass class]) forIndexPath:indexPath];
    [self configureMyCell:cell forIndexPath:indexPath];

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    MyCellClass * cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([MyCellClass class])];
    [self configureMyCell:cell forIndexPath:indexPath];

    CGFloat cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    return cellHeight;
}
TheCodingArt
  • 3,436
  • 4
  • 30
  • 53
1

In ios, the height of the cell is calculated in heightForRowAtIndexPath. What you are trying to do is to get height of the cell inside heightForRowAtIndexPath. It is definitely not the way to do it. To have dynamic height, calculate the height inside heightForRowAtIndexPath using the features/values you might need and return that height.

Bottom line is you cannot call cell.height inside heightForRowAtIndexPath.

Edit 1:

To help you deal with the dynamic heights in cell, please look at this tutorial. It might help you understand the issue : Dynamic Cell

Just go straight to the tableView delegates method to get an understanding of how to proceed.

rudedude
  • 723
  • 4
  • 18
  • I have a public property on my custom UITableViewCell called height which is where I'm calculating the height. But that is a bit confusing so I'll update question. – timpone Oct 07 '14 at 02:11
  • Actually, still the problem is same. heightForRowAtIndexPath is called before the cellForRowAtIndexPath is called. So your deliberate call will also result in an error. Try creating a method like getUpdatedHeight which calculates height (just like your updateCell method) on the basis of indexRow only. Then call that function in cellForRowAtIndexPath. – rudedude Oct 07 '14 at 03:09
  • There's actually a method in iOS for calculating the cell height on the fly in this method as such: CGFloat cellHeight = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; within the heightForRowAtIndexPath. For dynamic cell heights, you should use the above with auto layout for dynamic calculations. Remember, the cell itself doesn't have a height, the contentView does. But this answer also doesn't state why the above is crashing the app. – TheCodingArt Oct 07 '14 at 03:37
  • I cannot comment on crashing as i don't know exactly what the log is showing. I just know, that the approach is wrong, and that could be the reason to crash. – rudedude Oct 07 '14 at 03:55