Создание кластера классов в объекте c - методы, вызываемые в абстрактном суперклассе?

Я пытаюсь создать кластер классов для UITableViewDatasource. Мой интерфейс выглядит так:

@interface ArrayDataSource : NSObject <UITableViewDataSource>
- (id)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier configureCellBlock:(TableViewCellConfigureBlock)configurationBlock;
- (id)initWith2DArray:(NSArray *)array sectionIdentifiers:(NSArray *)cellIdentifiers configureCellBlock:(TableViewCellConfigureBlock)configurationBlock;
- (id)itemAtIndexPath:(NSIndexPath *)indexPath;
@end

Внутри абстрактный класс выглядит так:

@implementation ArrayDataSource

- (id)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier configureCellBlock:(TableViewCellConfigureBlock)configurationBlock {
    return [[SingleArrayDatasource alloc] initWithItems:items cellIdentifier:cellIdentifier configureCellBlock:configurationBlock];
}

- (id)initWith2DArray:(NSArray *)array sectionIdentifiers:(NSArray *)cellIdentifiers configureCellBlock:(TableViewCellConfigureBlock)configurationBlock {
    return [[TwoDimensionalArrayDatasource alloc] initWith2DArray:array sectionIdentifiers:cellIdentifiers configureCellBlock:configurationBlock];
}

Теперь, чтобы заставить замолчать компилятор, который жалуется, что абстрактный класс (ArrayDatasource) не реализует требуемые методы источника данных uitableview, я добавил их:

#pragma mark - Overrides
- (id)itemAtIndexPath:(NSIndexPath *)indexPath { return nil; }
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 0; }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 0; }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return nil; }

Но всякий раз, когда я использую кластер, вызовы источника данных переходят в абстрактный класс! Если я удаляю эти переопределения, все работает как нужно (за исключением того, что у меня все еще есть предупреждение компилятора).

Что здесь происходит? Почему эти сообщения отправляются в абстрактный класс, когда экземпляр SingleArrayDatasource или TwoDimentionalArrayDatasource?

ОБНОВИТЬ

вот как я реализовал один из конкретных подклассов

@implementation SingleArrayDatasource

- (id)initWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier configureCellBlock:(TableViewCellConfigureBlock)configurationBlock
{
    self = [super init];
    if (self) {
        self.items              = items;
        self.cellIdentifier     = cellIdentifier;
        self.configureCellBlock = [configurationBlock copy];
    }
    return self;
}

- (id)itemAtIndexPath:(NSIndexPath *)indexPath
{
    return self.items[indexPath.row];
}

#pragma mark UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.items.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    id cell = [tableView dequeueReusableCellWithIdentifier:self.cellIdentifier forIndexPath:indexPath];
    id item = [self itemAtIndexPath:indexPath];
    self.configureCellBlock(cell, item);
    return cell;
}

2 ответа

Одна вещь, которую вы должны сделать, это в ваших конкретных подклассах, не нужно вызывать супер инициализацию, так как вы уже вызываете alloc, которая будет выделять память. Кроме того, в вашем абстрактном классе перед вызовом метода инициализации конкретного класса установите для себя значение nil, чтобы не было никаких следов абстрактного класса. Как только вы это сделаете, вам не нужно удалять переадресацию.

Ваша проблема возникает из-за того, что Objective C на самом деле не имеет абстрактных типов, по крайней мере, не так, как в Java.

Кроме того, вы возвращаете преобразованный тип из init, который является методом экземпляра, что означает, что вы уже должны работать с экземпляром "абстрактного типа" - что нелогично.

Я предлагаю вам использовать фабричный шаблон в вашем "абстрактном классе" -

@implementation ArrayDataSource

+ (id)dataSourceWithItems:(NSArray *)items cellIdentifier:(NSString *)cellIdentifier configureCellBlock:(TableViewCellConfigureBlock)configurationBlock {
    return [[SingleArrayDatasource alloc] initWithItems:items cellIdentifier:cellIdentifier configureCellBlock:configurationBlock];
}

+ (id)dataSourceWith2DArray:(NSArray *)array sectionIdentifiers:(NSArray *)cellIdentifiers configureCellBlock:(TableViewCellConfigureBlock)configurationBlock {
    return [[TwoDimensionalArrayDatasource alloc] initWith2DArray:array sectionIdentifiers:cellIdentifiers configureCellBlock:configurationBlock];
}

Это методы класса, поэтому допустимо вызывать alloc и init

Другие вопросы по тегам