12

I've implemented automatic dynamic tableview cell heights for iOS 8 by using

self.tableView.rowHeight = UITableViewAutomaticDimension;

For pre-iOS 8, which does not support automatic dynamic cell heights, I overrided the heightForRowAtIndexPath method.

This is a similar to what I did: Using Auto Layout in UITableView for dynamic cell layouts & variable row heights

The problem is to how to write code that uses automatic cell height for iOS 8 but overrides heightForRowAtIndexPath for earlier iOS versions. I'd like my custom heightForRowAtIndexPath method only if iOS version is less than 8. Any suggestions on how to do this?

Community
  • 1
  • 1
amirfl
  • 1,634
  • 2
  • 18
  • 34
  • 3
    You might also consider just using a different data source in iOS 7 and iOS 8. (i.e. an object of a different class) – Jesse Rusak Sep 24 '14 at 17:07
  • @JesseRusak is absolutely correct, and this is the recommended practice. Create a class cluster for your data source which provides the appropriate concrete implementation at runtime. – quellish Jan 15 '15 at 02:42

2 Answers2

19

One solution would be to override the respondsToSelector: method in your view controller. Have it return NO under iOS 8 when checking for the heightForRowAtIndexPath: method.

- (BOOL)respondsToSelector:(SEL)selector {
    static BOOL useSelector;
    static dispatch_once_t predicate = 0;
    dispatch_once(&predicate, ^{
        useSelector = [[UIDevice currentDevice].systemVersion floatValue] < 8.0 ? YES : NO;
    });

    if (selector == @selector(tableView:heightForRowAtIndexPath:)) {
        return useSelector;
    }

    return [super respondsToSelector:selector];
}

This way, when the table view make a call like:

if ([self.delegate respondsToSelector:@selector(tableView:heightForRowAtIndexPath:)]) {
}

your code will return NO under iOS 8 or later and YES under iOS 7 or earlier.

mluisbrown
  • 14,448
  • 7
  • 58
  • 86
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • I added this as a category for `UITableViewController`, so you don't have to add it to every single one. Also you can test if the selector is `tableView:estimatedHeightForRowAtIndexPath:`, since I believe that is also not needed for iOS8. – koen Sep 28 '14 at 17:15
  • @Koen It's dangerous to override a method in a category since that is undefined behavior. It may work or it may not. – rmaddy Sep 28 '14 at 17:18
  • Good point, I will remove the category and add this to every `UITableViewController` – koen Sep 28 '14 at 17:39
  • 2
    @Koen A better solution is to create your own subclass of `UITableViewController` and add the method there. That have all of your table view controller extend your custom class. – rmaddy Sep 28 '14 at 17:40
1

I found a simple solution. Declared this macro to recognize if user has iOS 8.0 or later:

#define IS_IOS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)

Then, inside heightForRowAtIndexPath I added the following code:

if (IS_IOS_8_OR_LATER) {
        self.tableView.rowHeight = UITableViewAutomaticDimension;
        return self.tableView.rowHeight;
    } else {//Custom code for ios version earlier than 8.0

}

This solved the problem

rmaddy
  • 314,917
  • 42
  • 532
  • 579
amirfl
  • 1,634
  • 2
  • 18
  • 34
  • 1
    The downside to this approach is you lose a lot of the performance gain. Since the table sees that you implement the `heightForRowAtIndexPath` delegate method, it calls it for every row. My solution gives you back the performance gain. – rmaddy Sep 24 '14 at 16:58