如何在单个表中使用两个不同的自定义UITableViewCell子类?

时间:2013-12-19 19:24:54

标签: ios cocoa-touch uitableview

如何在同一个UITableView中正确显示不同的UITableViewCell子类?

我正在使用故事板来解决这个问题。我试图在一个表中使用两个不同的UITableView单元子类。 TTTextFieldCell知道如何显示文本框和TTPickerCell知道如何向用户呈现UIPicker的想法。协议TTTableViewCell指定了一个选择器:[setCellDetails (NSDictionary*) cellDetails]每个UITableViewCell子类知道如何处理cellDetails字典来设置单元格。

-(NSArray *)tableData {
     if (!_tableData) {
          _tableData =
          @[ // Sections
             @{ // Section Details
                  kSectionName:@"Scout Information"
                  ,kRows:@[ // Rows
                             @{// Cell Details
                                  kBoundProperty:self.scoutName
                                  ,kReuseIdentifier:kTextFieldCell
                                  ,kLabel:@"Name"
                                  ,kPlaceholderValue:@"Scout's Name"
                                  }
                             ,@{
                                  kReuseIdentifier:@"TTPickerCell"
                                  ,kLabel:@"Type"
                                  ,kPlaceholderValue:@"Cadet, Junior, etc..."
                                  }
                             ,@{
                                  kBoundProperty:self.yearsScouting
                                  ,kReuseIdentifier:kTextFieldCell
                                  ,kLabel:@"Years"
                                  ,kPlaceholderValue:@"Years of Experience"
                                  ,kKeyboardStyle:@(UIKeyboardTypeNumberPad)
                                  }
                             ]
                  }
             ,@{ // Section Details
                  kSectionName:@"Parent Information"
                  ,kRows:@[
                             @{
                                  kBoundProperty:self.parentName
                                  ,kReuseIdentifier:kTextFieldCell
                                  ,kLabel:@"Name"
                                  ,kPlaceholderValue:@"Parents's Name"
                                  }
                             ]
                  }
             ];
     }
     return _tableData;
}


- (void)viewDidLoad
{
     [super viewDidLoad];
    // Do any additional setup after loading the view.
    // Line A
     [self.tableView registerClass:[TTTextFieldCell class] forCellReuseIdentifier:@"TTTextFieldCell"];
    // Line B
     [self.tableView registerClass:[TTPickerCell class] forCellReuseIdentifier:@"TTPickerCell"];
}


-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
     NSDictionary* cellDetails = self.tableData[indexPath.section][kRows][indexPath.row];

     NSString* reuseIdentifier = cellDetails[kReuseIdentifier];

     // Line C
     UITableViewCell<TTTableViewCell> *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

     [cell setCellDetails:cellDetails];
     return cell;
}

现在,问题就在这里。如果我注释掉A行和B行,则TTTextFieldCells会正确显示。但是C行会失败,因为它试图用TTPickerCell对象调用TTTextFieldCell init,并且由于TTPickerCell对象没有相同的属性而失败。如果我取消注释A行和B行,则单元格样式默认为UITableViewCellStyleDefault,并且它们不显示自定义控件。奇怪的是,如果我注释掉A行,并取消注释B行,那么TTTextFieldCells看起来很棒,但TTPickerCells默认为UITableViewCellStyleDefault

似乎如果我没有注册一个类,dequeue将返回第一个原型单元类的实例。如果我注册该类,则单元格默认为UITableViewCellStyleDefault

另外值得注意的是,只有在注册类时才会调用initWithStyle:reuseIdentifier:selectors。

那么,如何在同一个UITableView中正确显示不同的UITableViewCell子类?我是否必须放弃使用故事板来设计单元格?

提前谢谢。

3 个答案:

答案 0 :(得分:1)

您不希望在tableView registerClass:...内拨打cellForRowAtIndexPath。相反,您应该一次注册您的类/笔尖。这通常在控制器的viewDidLoad方法中完成。您的cellForRowAtIndexPath实现可能如下所示:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSDictionary* cellDetails = self.tableData[indexPath.section][kRows][indexPath.row];

    NSString *reuseIdentifier = (/*some condition*/ ? @"TTTextFieldCell" : @"TTPickerCell");
    UITableViewCell<TTTableViewCell> *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    [cell setCellDetails:cellDetails];
    return cell;
}

编辑:我应该提到dequeueReusableCellWithIdentifier总是从iOS 6返回一个单元格。如果你的目标是早期版本的iOS,你需要考虑创建单元格,即使这个方法返回nil。

答案 1 :(得分:0)

好的,这就是我发现的答案。

  1. 不要为重用标识符注册类。注释掉A行和B行。
  2. 除非您仔细检查IBOutlets,否则不要复制和粘贴原型单元格。粘贴的原型单元格并不关心您为其分配的UITableViewCell子类,它不会验证IBOutlets是否存在。
  3. 修正了#2,一切都很顺利。

    卫生署!

答案 2 :(得分:-1)

我使用从NIB和NSMutable数组加载的两种类型的单元格与我的对象,对象具有我想在单元格中使用的文本,标题和图像。在方法cellForRowAtIndexPath ...中,将对象中的内容放入单元格。你可以在没有笔尖的情况下初始化。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (your condition){
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CellClass1" owner:self options:nil];
        CellClass1  *cell =  (CellClass1 *)[topLevelObjects objectAtIndex:0];
        }else{
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@"CellClass2" owner:self options:nil];
        CellClass2  *cell =  (CellClass2 *)[topLevelObjects objectAtIndex:0];}

        //get your content for cell at array or your own estructure 
        Content *content = [contents objectAtIndex:indexPath.row];


        cell.description.text = content.description;

        return cell;
    }