我想创建一个继承自 UITableView 的新类 MYTableView。MYTableView 将有一个 NSArray 属性来存储它的所有数据。这意味着我不再需要担心实现numberOfRows
and cellForRow
,因为 MYTableView 将是它自己的数据源并提供必要的数据。另外,我希望 MYTableView 在didSelectRow
方法中有一些自定义逻辑,所以我也将它设置为它自己的委托。
现在问题来了……我有一个 TVC(一个 UITableViewController)对象,它有一个 MYTableView 实例。我想覆盖didSelectRow
方法中的逻辑。也就是说,除了 TVC 的逻辑之外,我还希望 MYTableView 的逻辑发生。
解决方案1: tableView.delegate = TVC
显然这行不通。如果我尝试将 tableView 的委托设置回 TVC,那么是的,TVC 的 didSelectRow 方法被调用,但是 MYTableView 的逻辑永远不会被调用,因为我们劫持了委托。
解决方案 2: tableView.delegate2 = TVC
我可以创建第二个委托(参见下面的代码)并将 TVC 设置为委托 2。然后,我将从 tableView.delegate 的 didSelectRow 方法中调用 delegate2 的 didSelectRow 方法。
问题:
- 拥有
delegate
和delegate2
是丑陋的。此外,如果用户将委托设置为其他内容,事情就会中断。 - 我必须转发 TVC 可能想要实施的每一个事件。
问题:
因为这不是最佳解决方案。你能想出更好的解决方案吗?
如果我无法控制继承的类(例如,如果我从 UITableView 继承),我有什么选择?
如果我确实可以控制继承的类(例如,我正在使用我拥有其源代码的假设 UITableView),那么实现它以允许这种功能的最佳方法是什么?
笔记:
- 目前
didSelectRow
在这些示例中只有 1 行代码。显然,如果它只有一行代码,那么这不会是一个大问题,我会找到解决它的方法。真正的代码是多行代码。
完整代码如下:(对于解决方案2)
// ---------------------------------------------------
// VC.m
// ---------------------------------------------------
@implementation VC
- (MYTableView *)myTableView {
return (MYTableView *)self.tableView;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
self.myTableView.delegate2 = self;
}
- (void)insertNewObject:(id)sender
{
static NSInteger i = 0;
if (i % 3 == 0) {
[self.myTableView insertObject:[NSNull null] inDataArrayAtIndex:0];
} else {
[self.myTableView insertObject:[NSDate date] inDataArrayAtIndex:0];
}
i++;
}
#pragma mark - MYTableViewDelegate
- (void)myTableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(@"Selected row: %@", indexPath);
}
@end
// ---------------------------------------------------
// MYTableView.h
// ---------------------------------------------------
@class MYTableView;
@protocol MYTableViewDelegate <UITableViewDelegate>
@optional
- (void)myTableView:(MYTableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
@end
@interface MYTableView : UITableView <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, weak) id<MYTableViewDelegate> delegate2;
- (void)insertObject:(NSObject *)object inDataArrayAtIndex:(NSUInteger)index;
@end
// ---------------------------------------------------
// MYTableView.m
// ---------------------------------------------------
@interface MYTableView ()
@property (nonatomic, strong) NSMutableArray *dataArray;
@end
@implementation MYTableView
- (void)commonInit {
self.dataArray = [NSMutableArray array];
self.dataSource = self;
self.delegate = self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self commonInit];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (void)insertObject:(NSObject *)object inDataArrayAtIndex:(NSUInteger)index {
[self.dataArray insertObject:object atIndex:index];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
[self insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.dataArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString * const identifier = @"String Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.textLabel.text = [self.dataArray[indexPath.row] description];
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSObject *object = self.dataArray[indexPath.row];
if ([NSNull null] == object) {
[self deselectRowAtIndexPath:indexPath animated:YES];
}
if ([self.delegate2 respondsToSelector:@selector(myTableView:didSelectRowAtIndexPath:)]) {
[self.delegate2 myTableView:self didSelectRowAtIndexPath:indexPath];
}
}
@end