我想创建一个继承自UITableView的新类MYTableView。 MYTableView将具有存储其所有数据的NSArray属性。这意味着我不再需要担心实现numberOfRows
和cellForRow
,因为MYTableView将是它自己的数据源并提供必要的数据。另外,我希望MYTableView在didSelectRow
方法中有一些自定义逻辑,所以我将其设置为自己的委托。
现在问题是......我有一个TVC(一个UITableViewController)对象,它有一个MYTableView实例。我想覆盖didSelectRow
方法中的逻辑。也就是说,除了TVC的逻辑之外,我还希望MYTableView的逻辑发生。
解决方案1: tableView.delegate = TVC
显然这不起作用。如果我尝试将tableView的委托设置回TVC,那么是的,TVC的didSelectRow方法被调用,但是MYTableView的逻辑从未被调用,因为我们劫持了委托。
解决方案2: tableView.delegate2 = TVC
我可以创建第二个代理(参见下面的代码)并将TVC设置为delegate2。然后我会从tableView.delegate的didSelectRow方法中调用delegate2的didSelectRow方法。
问题:
delegate
和delegate2
变得丑陋。此外,如果用户将委托设置为其他内容,则事情会中断。问题:
因为这不是最佳解决方案。你能想到更好的解决方案吗?
如果我无法控制继承的类(例如,如果我继承自UITableView),我的选择是什么?
如果我确实可以控制继承的类(例如我使用的是我拥有源代码的假设UITableView),那么实现它以实现这种功能的最佳方法是什么?
注意:
didSelectRow
目前在这些示例中只有一行代码。显然,如果它只是一行代码,那么这不是一个大问题,我会找到解决方法。真正的代码是许多代码行。// ---------------------------------------------------
// 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
答案 0 :(得分:0)
您可以使用两个委托,但覆盖setDelegate方法,使事物至少看起来更干净。我在UITextView的子类中做了类似的事情:https://github.com/mbachrach/GCPTextView
答案 1 :(得分:0)
如果您创建了一个单独的类,它只是根据您的数据源实现UITableViewDataSource协议,那该怎么办?这可以是一个NSObject,或者我想你的MyTableView,如果你真的想这样做的话。这是一个非常高度可重复使用的课程,将使您的生活更加轻松。
对于双委托问题,如果您通过MyTableView中的UITableViewDelegate处理行的选择但设置了基于块的系统来选择视图控制器,该怎么办呢?
void(^RowSelected)(void)(NSObject *selectedObject, NSIndexPath *indexPath)