How to access properties in multiple custom tablev

2019-09-15 18:17发布

问题:

I created two custom TableViewCells and successfully register them with the UITableView.

They both have different properties. Question is, how do I access these properties?

NSDictionary *dict = self.tblContent[indexPath.row];

    NSString *identifier;

    if ([dict[@"type"] isEqualToString:@"type1"]) {
        identifier = @"cell1";
    }else if ([dict[@"type"] isEqualToString:@"type2"]) {
        identifier = @"cell2";
    }

    CustomCell1 *cell = [tableView dequeueReusableCellWithIdentifier:identifier];

    cell.lblWho.text = dict[@"name"];
    cell.lblWhen.text = dict[@"date"];

    if ([dict[@"type"] isEqualToString:@"type2"]) {

        (CustomCell2 *)cell.specialField.text = @"special field";
    }

Both cells have a lblWho and a lblWhen, but only cell2 has the specialField. When I try to access it, XCode complains that CustomCell1 doesn't have the property specialField (of course). As you can see, I tried to cast the cell to CustomCell2, but this doesn't work.

How do I have to setup the cells so I can access the properties that are unique to the cell?

回答1:

Best approach in that case (imo) is:

  1. Create MyCell (inherited from UITableViewCell).
  2. Change @interface CustomCell2 : UITableViewCell to @interface CustomCell2 : MyCell
  3. Move common properties to MyCell
  4. Make function in MyCell and implement it in subclasses

(void) configureCellForDictionary:(NSDictionary *) dict

And use it:

MyCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
[cell configureCellForDictionary:dict]

Using this approach you'll hide details of how cell displays its content to cell class + you can move all common code to cell's superclass

More structured data to read about making controllers thiner: Lighter View Controllers and Clean table view code



回答2:

The problem is with operator precedence on the cast. This line:

(CustomCell2 *)cell.specialField.text = @"special field";

Is casting more than you want. Try a more qualified:

((CustomCell2 *)cell).specialField.text = @"special field";

Incidentally @NikitaTook gives a good answer about design. Breakup the code by cell type. But the more immediate issue is the cast.

For posterity, the common superclass avoids the cast problem, but is not always prudent or possible. Here's how one deals with conditional types in general...

// declare the variable in question as the lowest common ancestor on
// the class hierarchy, use id when the variable can be any class
// for this problem, we know they are UITableViewCells at least...
UITableViewCell *cell = [tableView dequeue...

// add a conditional that determines the type.  In this case, the
// kind of cell we want is based on the model, but this can be any condition...
if ([dict[@"type"] isEqualToString:@"type1"]) {

    // declare a new local of the now-known, more specific type.
    // initialize it with a cast of the abstractly declared instance
    MyTableViewCellSubtypeA *cellTypeA = (MyTableViewCellSubtypeA *)cell;

    NSLog(@"%@", cellTypeA.propertySpecificToA);  // use it specifically

    // if you're lazy, or just have a one-liner, cast as I suggest, using parens properly
    (MyTableViewCellSubtypeA *)(cell).propertySpecificToA;

Same idea for the else branch.



回答3:

  1. You can check class of the cell:

    if ([cell isKindOfClass: [CustomCell1 class]])
    {
         //Customize customcell1
    }
    else
    {
         //Customize customcell2
    }
    
  2. You can check if your cell has "specialField" property:

    if ([cell respondsToSelector: @selector(specialField)])
    {
        //Custom cell 2
    }
    else
    {
        //Custom cell 1
    }