0

UITableView を継承する新しいクラス MYTableView を作成したいと考えています。MYTableView には、そのすべてのデータを格納する NSArray プロパティがあります。これは、MYTableView が独自のデータソースになり、必要なデータを提供するため、 and のnumberOfRows実装について心配する必要がなくなったことを意味します。cellForRowさらに、MYTableView のdidSelectRowメソッドにいくつかのカスタム ロジックを持たせたいので、独自のデリゲートとしても設定します。

ここに問題があります... MYTableView インスタンスを持つ TVC (UITableViewController) オブジェクトがあります。didSelectRowメソッド内のロジックをオーバーライドしたい。つまり、TVC のロジックに加えて MYTableView のロジックが発生するようにしたいということです。

解決策 1: tableView.delegate = TVC
明らかにこれは機能しません。tableView のデリゲートを TVC に戻そうとすると、TVC の didSelectRow メソッドが呼び出されますが、MYTableView のロジックは呼び出されません。これは、デリゲートをハイジャックしたためです。

解決策 2: tableView.delegate2 = TVC
2 番目のデリゲートを作成し (以下のコードを参照)、TVC をデリゲート 2 に設定します。次に、tableView.delegate の didSelectRow メソッド内から delegate2 の didSelectRow メソッドを呼び出します。

問題:

  • 持ちdelegatedelegate2醜い。さらに、ユーザーがデリゲートを別のものに設定すると、問題が発生します。
  • TVC が実装する可能性のあるすべてのイベントを転送する必要があります。

質問:

これは最適なソリューションではないためです。より良い解決策を考えられますか?

継承されたクラスを制御できない場合 (たとえば、UITableView から継承している場合)、どのようなオプションがありますか?

継承されたクラスを制御できる場合 (たとえば、ソース コードを所有する架空の UITableView を使用している場合)、この種の機能を可能にするためにそれを実装する最良の方法は何でしょうか?

ノート:

  • 現在didSelectRow、これらの例には 1 行のコードしかありません。明らかに、それがたった 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
4

3 に答える 3

0

データソースに基づいて UITableViewDataSource プロトコルを実装するだけの別のクラスを作成したらどうでしょう。これは NSObject にすることも、本当にそのようにしたい場合は MyTableView にすることもできます。これは非常に再利用可能なクラスであり、将来の生活を楽にしてくれます。

二重デリゲートの問題については、MyTableView の UITableViewDelegate を介して行の選択を処理し、ビュー コントローラーを選択するためのブロック ベースのシステムをセットアップした場合はどうなるでしょうか。

void(^RowSelected)(void)(NSObject *selectedObject, NSIndexPath *indexPath)
于 2013-10-17T01:36:19.183 に答える