1
votes

I have an application that was not originally a storyboard application. I've since added a storyboard for a feature branch, and there is a subclass of UITableViewController on it. I've created a prototype cell with several UILabels and UIImageViews, and added tags for each of them. The prototype cell has the correct identifier.

I've registered the class with the identifier:

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CustomCell"];

When I try to dequeue the custom cell and access its views:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:indexPath];
UIImageView *icon = (UIImageView *)[cell viewWithTag:1];

The view (icon) is nil.

I've also tried subclassing it, and registering the subclass with the reuse identifier, and setting the UITableViewCell with the subclass name in the prototype. In that case,

UIImageView *icon = cell.icon; 

still returns nil.

Is there something to do with the storyboard not being the main one? I've had other projects where prototype cells with custom subviews just works fine without all of this trouble. Is there a way to register the custom class or UITableViewCell with custom identifier, but specify which storyboard it's from?

1
You don't need to register the class if you are using the prototype cell in a storyboard. Simply make sure the custom class is set correctly in the prototype cell and that the IBOutlets are assigned.Paulw11
Have you attempted using [cell.contentView viewWithTag:1]?andrewbuilder
yes, i tried it with contentView as well, and it also returned nil.mitrenegade

1 Answers

5
votes

Ok I've figured it out, and I'm going to answer in order to put down a few small things I've learned.

My controller was being instantiated using alloc/init instead of

[_storyboard instantiateViewControllerWithIdentifier:@".."]. 

That means the storyboard was never used, and the prototype cells were never registered.

So when a secondary storyboard is used and a controller is instantiated programmatically and not through a segue, make sure to use instantiateViewControllerWithIdentifier.

Do not register cells or register a custom class:

// don't do this
[self.tableView registerClass:[ClaimsCell class] forCellReuseIdentifier:@"ClaimsCell"];

Dequeue the cell using:

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AddClaimCell" forIndexPath:indexPath];

That way, the compiler will actually inform you that the prototype cell has not been connected. Don't be tempted to use the old tableview dequeue call:

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AddClaimCell"];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CustomCell"];
    }

Because if you've hooked up the storyboard right, cell will always get returned by the forIndexPath: call.

I've chosen to use UITableViewCell with view tags instead of making custom classes. But the prototype cell can be set as a custom UITableViewCell subclass, and the individual cell elements can be referenced if they have been connected in the storyboard.

instantiating a UITableViewCell:

    UIImageView *icon = (UIImageView *)[cell viewWithTag:1];
    UILabel *labelDescription = (UILabel *)[cell viewWithTag:2];
    UILabel *labelStatus = (UILabel *)[cell viewWithTag:3];

instantiating a CustomCell:

    UIImageView *icon = cell.iconStatus;
    UILabel *labelDescription = cell.labelDescription;
    UILabel *labelStatus = cell.labelStatus;