I have a table view with dynamically sized cells. This works great in iOS 8 but it's not supported in iOS 7. I'm required to implement tableView:heightForRowAtIndexPath or the app will crash in iOS 7. If I do that, I'm going to have to calculate the height of the cell. The problem is that if I implement this method, iOS 8 pays attention to it and no longer does its dynamically sized cell magic. Is there any way to only implement this method for iOS 7 clients?
3 Answers
I have used something similar to this before:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:@"CellIdentifier"];
// Stuff & Things
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
return [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
}

- 559
- 3
- 11
-
1Swift, this actually works, but only if you do for the cell, not the contentView > cell.setNeedsLayout() > cell.layoutIfNeeded() Some ios7 compatibility won't hurt anyone =D – soprof Jul 17 '15 at 14:34
The new internal autolayout self-sizing cells from iOS 8 cannot magically be reflected back to iOS 7. But that's not a problem. If you want to be backwards-compatible to iOS 7, then, as you rightly say, this means that you will determine the cell height yourself, so that you can return the correct value from tableView:heightForRowAtIndexPath:
. This is what we did in iOS 4, 5, 6, and 7. That will still work in iOS 8 too (and is probably faster anyway).
So my advice would be: just write the code as if for iOS 7. If you're coding in Objective-C you could have two different sets of code (conditional compilation), and even in Swift you could use two different classes, depending on what system we find ourselves on; but I regard that as a bit over the top - it's a code maintenance nightmare waiting to happen.

- 515,959
- 87
- 875
- 1,141
-
Thanks, I guess I was trying to have the best of both worlds and have iOS 8 use its magic and anything before that use heightForRowAtIndexPath. It sounds like that's not possible.. – Chris Williams Jan 14 '15 at 20:26
-
It's possible but (in my view) not worth the trouble. I'll add something to my answer... – matt Jan 14 '15 at 20:27
-
This is not really an answer. How would conditional compilation for this method work? That would be the answer to the question. And it doesn't seem like an unreasonable question, just because it was more difficult in the past doesn't mean it's not worth taking a shortcut to use the new API now. For instance, one might want to return a hard-coded or estimated value for ios7 just so the app still runs, but not invest time getting subtle auto-layout sizing differences to work perfectly since the ios7 userbase is much smaller than ios8 at this point – danny Apr 29 '15 at 00:09
-
@danny It _is_ an answer: it's my answer. It's what I do: if my app is to be backwards compatible, I go right on using `systemLayoutSizeFittingSize:` in my implementation of `heightForRow...` and using internal constraints to determine the cell height. It works in iOS 7 and iOS 8, and it is in fact all that the "new" iOS 8 feature is doing anyway! And I have fully explained this technique in my book. So, if you have a different answer, give it. But don't tell me my answer is no answer. It's a great answer. – matt Apr 29 '15 at 01:07
I got UIViewAlertForUnsatisfiableConstraints
error in debug log.
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "", "", "" )
If there is no tableView:heightForRowAtIndexPath:
, the cell looks fine. So, I want to disable it in iOS 8. @batu gave a solution in another post: Implement heightForRowIndexPath: in iOS 7, but remove it in iOS 8 using compile-time macro. Thanks to @batu, the solution is as simple as this:
#define IS_IOS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
-(CGFloat) tableView: (UITableView * ) tableView heightForRowAtIndexPath: (NSIndexPath * ) indexPath {
if (IS_IOS_8_OR_LATER) {
return UITableViewAutomaticDimension;
}
// Your iOS 7 code here.
}
However, my cell still has problem with the height in iOS 8 with iPhone 6. The causes seems to be the fixed width of UILabel (which is designed for 320pt). Here is what I did after a long night research:
I applied the solution from this guide: Dynamic Table View Cell Height and Auto Layout.
Since the UILabel requires explicit width for iOS 7 device, I programmatically "clear" this settings for iOS 8. In my extended table view cell:
- (void)awakeFromNib { // Initialization code if (IS_IOS_8_OR_LATER) { self.descriptionLabel.preferredMaxLayoutWidth = 0; } }
I used the
RWLabel
suggestion as from the guide.I disable
return UITableViewAutomaticDimension;
. Whether enable or disable, may depends on the subviews and constraints in table view cell. Try to fit your case.I change the priority of the Trailing Space for all RWLabel to 999 (instead of 1000). That eliminates the unsatisfiable constraints warning.
Hopefully these solutions would help someone.