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?
Best approach in that case (imo) is:
- Create MyCell (inherited from
UITableViewCell
).
- Change
@interface CustomCell2 : UITableViewCell
to @interface CustomCell2 : MyCell
- Move common properties to
MyCell
- 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
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.