简体   繁体   中英

Creating a class cluster in objective c - methods called on abstract super class?

I'm trying to create a class cluster for a UITableViewDatasource. My interface looks like this:

@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

Internally, the abstract class looks like this:

@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];
}

Now, in order to silence the compiler, who is complaining that the abstract class (ArrayDatasource) doesn't implement the uitableview datasource required methods, i've added these:

#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; }

But whenever I use the cluster, the datasource method calls go to the abstract class! If i delete those overrides, everything works as desired (except i still have the compiler warning).

What is going on? Why are those messages going to the abstract class when the instance is a SingleArrayDatasource or a TwoDimentionalArrayDatasource ?

UPDATE

here is how I implemented one of the concrete subclasses

@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;
}

Your problem is occurring because Objective C doesn't really have abstract types, at least not in the way that Java does.

Also, you are returning a morphed type from init, which are instance methods, which means that you must already be operating on an instance of "abstract type" - which is illogical.

I suggest you use a factory pattern in your "abstract class" -

@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];
}

These are class methods so it is valid to call alloc and init

One thing you have to do is in your concrete subclasses, no need to call super init, as you are already calling alloc, which will do the memory allocation. Also, in your abstract class, before calling concrete class initialisation method set self to nil, so that there won't be any trace of abstract class. Once you do that you don't need to delete the over rides.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM