且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为iOS7和iOS8重构UITableView代理

更新时间:2023-02-03 09:42:55

self.tableView setDelegate:分配一个 weak reference;如果你没有自己的引用这个对象,它将被收集。这就是为什么你看到崩溃。系统已收集分配给您的代理的内存,然后将内存重新分配给一个 NSArray 。您的表尝试调用委托方法,因为 NSArray 不对其进行响应。



self.tableView 属性定义,定义另一个属性:

  @property (strong)id  


As a follow up to this question: Skip/ignore method in iOS, I'm trying to implement separate delegates for my UITableView in iOS7 and iOS8.

So, as a first step, in viewDidLoad of my MyTableViewController, I added the following code:

if ([[[UIDevice currentDevice] systemVersion] compare: @"8.0" options: NSNumericSearch] != NSOrderedAscending)
{
    [self.tableView setDelegate: [[MyTVDelegate alloc] initWithIdentifier: myTVCellIdentifier]];
}
else
{
    [self.tableView setDelegate: [[MyTVDelegate7 alloc] initWithIdentifier: myTVCellIdentifier]];
}

I'm adding an identifier, since I will have to apply this to multiple view controllers (or I may have just create a delegate class for each TV, I haven't figured that out yet).

I'm using CoreData, so my dataSource is an NSFetchedResultsController.

Then, I have the following for MyTVDelegate/myTVDelegate7:

#import "MyTVDelegate.h"

@implementation MyTVDelegate

- (instancetype)initWithIdentifier: (NSString *) identifier
{
    if ([super init])
    {
        self.identifier = identifier;
    }

    return self;
}

@end

@implementation MyTVDelegate7

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

- (CGFloat)tableView: (UITableView *)tableView estimatedHeightForRowAtIndexPath: (NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}

@end

If I run this, I'm getting the following runtime error in iOS7:

2015-01-18 10:42:51.894  -[__NSArrayI tableView:estimatedHeightForRowAtIndexPath:]: unrecognized selector sent to instance 0x7b9dd220
2015-01-18 10:42:57.731  *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI tableView:estimatedHeightForRowAtIndexPath:]: unrecognized selector sent to instance 0x7b9dd220'

on iOS8, there is no crash.

The instance 0x7b9dd220 is an NSArray. My hunch is that it crashes, because the indexPath is invalid because the delegate and 'dataSource' are now separate?

I've tried moving the call to performFetch to either before or after setting the delegate, but I get the same error.

How do I fix this, should I for instance move all the NSFetchedResultsController code to the new delegate class as well?

self.tableView setDelegate: assigns a weak reference; if you don't hold your own reference to this object, it will get collected. This is why you're seeing the crash. The system has collected the memory that was assigned to your delegate, then reassigned the memory to an NSArray. Your table tries to call methods on the delegate and can't because NSArray does not respond to them.

Alongside the self.tableView property definition, define another property:

@property (strong) id<UITableViewDelegate> myTableViewDelegate;