在UITableViewCells的cellForRowAtIndexPath方法中实现多态

时间:2014-12-24 02:27:34

标签: ios objective-c uitableview ios7 polymorphism

我有一个genericTableViewController - GTBVC - 类,它被当前另外两个视图控制器所引导,每个视图控制器都有自己的数据数组,并传递给这个GTBVC

目前我的代码如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    id object = [self.genericArray objectAtIndex:indexPath.row];
    NSString *textNameOfObject = [[self.genericArray objectAtIndex:indexPath.row] performSelector:@selector(name)];

#warning - todo: Create a polymorphistic method for each uitableviewcells.

    if([object isMemberOfClass:[OXPersonModel class]]){
        OXFriendTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTableViewCellFriendIdentifier forIndexPath:indexPath];
        cell.friendNameLabel.text = textNameOfObject;


        [PKQuickMethods setCornerRadiusForView:cell.friendImageView withCornerRadius:CGRectGetWidth(cell.friendImageView.frame)/2];
        cell.friendImageView.image = [UIImage imageNamed:@"image"];
        [cell.friendImageView setContentMode:UIViewContentModeScaleToFill];
        return cell;
    }
    else if([object isMemberOfClass:[OXTagPlaceCountModel class]]){
        OXTagTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTableViewCellTagIdentifier forIndexPath:indexPath];
        cell.tagNameLabel.text = textNameOfObject;
        cell.tagPlacesCountLabel.text = [[self.genericArray objectAtIndex:indexPath.row] performSelector:@selector(totalPlacesCountString)];
        return cell;
    }
    return nil;
}

到目前为止,这种方法并不太糟糕。但是,因为我希望我的代码可以在未来扩展 - 当我扩展程序以满足其他单元格和产品类型时 - 我需要确保它易于实现。

我想到了多态性。我在想每个UITableView子类都需要实现一个公共方法名称,例如-[cell updateForModelObject:],这样最终cellForRowAtIndexPath只会有几行代码。

但是我发现自己想象我仍然需要根据标识符确定哪些单元格出列。要出列的单元格取决于self.genericArray中的对象类型。

如何在不使用任何if语句的情况下在cellForRowAtIndexPath多态内部创建当前代码?

3 个答案:

答案 0 :(得分:3)

您所描述的方法通常可以使用协议来实现。以下是:

在您的GTBVC标头中,声明一个协议,例如:

@protocol GTBVCCellConfiguration
   -(void)updateForModelObject:(id)anObject;
@end

然后创建您的UITableViewCell子类,使它们符合该协议并让它们实现该方法。在子类中,您可以换出" id"您期望的实际数据类型的参数类型。

由于您的通用表视图控制器将处理不同类型的数据,您可以声明一个Enum来指定您的通用tableview控制器可以采用的各种模式:

typedef NS_ENUM(NSInteger, GenericTableViewMode) {
  case GenericTableViewModePerson,
  case GenericTableViewModePlace
};

然后在您的GTBVC标题中,声明该类型的属性:

 @property (assign, nonatomic) GenericTableViewMode tableViewMode

在馈线视图控制器中,导入该GTBVC标头并实现准备segue:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([segue.identifier isEqualToString:#yourSegueIdentifierForPerson#]) {
       ((GenericTableViewController *)segue.destinationViewController).mode = GenericTableViewModePerson; 
   } else {
       // check for the next storyboard identifier and set the mode
   }
 }

然后在你的cellForRowAtIndexPath中(用一些简写):

-(void)tableView:cellForRowAtIndexPath: {
   id object = [self.genericArray objectAtIndex:indexPath.row];

   UITableViewCell <GTBVCellConfiguration> *cell = nil;

   switch (self.mode) {
     case GenericTableViewModePerson:
         cell = [tableView dequeueResuableCellWithIdentifier:@"PERSON" forIndexPath:indexPath];
     case GenericTableViewModePlace:
         cell = [tableView dequeueResuableCellWithIdentifier:@"PLACE" forIndexPath:indexPath];
   }

   [cell updateForModelObject:object];
   return cell;
 }

如果您愿意,您甚至可以创建一个方法,为tableview的当前模式返回正确的标识符。

答案 1 :(得分:1)

我的建议还包括protocol,而是您在模型对象上放置的协议。它可以有一个像-(NSString*)cellIdentifier这样的方法,它返回该模型类的唯一标识符。然后,您只需通过获取该索引的模型对象从表视图中出列。此外,您可以在模型协议上定义单元用于配置的方法。

这意味着您可以定义任何符合此协议的对象,现在可以在任何地方使用您的单元格。

答案 2 :(得分:0)

使用convention over configuration并按照模型类型确定的方式命名您的单元格标识符,例如,

NSString *modelClassName = NSStringFromClass(model.class);
NSString *modelCellClassIdentifier = [modelClassName stringByAppendingString:@"TableViewCellIdentifier"];
UITableViewCell<ModelUpdatable> *cell = [tableView dequeuReusableCellWithIdentifier:modelCellClassIdentifier];
[cell updateWithModel:model];

因此,如果您的模型名为Person,则您的单元格标识符为PersonTableViewCellIdentifier。 (我建议您调用您的手机PersonTableViewCell。)

我使用这种技术经常使用宏来声明标识符,我将尝试从内存中重现这些标识符,因此将其视为伪代码:

PRODeclareCellIdentifier(model) extern NSString *const model##TableViewCellIdentifier
PRODefineCellIdentifier(model) NSString *const model##TableViewCellIdentifier = @#model##TableViewCellIdentifier

在您的手机标题中,您要说PRODeclareCellIdentifier(Person)。在实施过程中,您要说PRODefineCellIdentifier(Person)。我谨慎地使用宏,但它们对于这样的样板来说非常非常有用。