Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView cells not nil at initialization

I am setting up my UITableView using storyboard editor. For creating my cells I am using the standard delegate method:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchResultCell"];
        if (cell == nil)
        {
        // Do cell setup
        }
    // etc
    return cell;
}

Except when the cell is dequeued the very first time it's not nil, as it should be. So the code inside the if statement is never executed.

People get this error when their reuse identifiers are inconsistent, so I went ahead and verified that I am using the exact same reuse identifier in my storyboard views as I do in my code. Still facing the issue. I also have several tableviews within the project and each one has a unique reuse identifier. Still no dice. Anyone know anything else that could be wrong here?

like image 517
Andrew Lauer Barinov Avatar asked Dec 17 '22 01:12

Andrew Lauer Barinov


1 Answers

That's not how UITableView works anymore. Reading your question, I think you might be confused about how it worked before as well. If not, sorry, the first part of this is just review. :)

Without storyboard cell prototypes

Here's how it used to work:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    // If the tableview has an offscreen, unused cell of the right identifier
    // it will return it.
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchResultCell"];
    if (cell == nil)
    {
        // Initial creation, nothing row specific.
    }

    // Per row setup here.

    return cell;
}

Here when you create the cell using the reuse identifier, you do only the initial setup here. Nothing specific to this particular row/indexPath.

Where I've put the Per row setup comment you have a cell of the right identifier. It may be a fresh cell, or a recycled cell. You're responsible for all setup related to this particular row/indexPath.

Example: if you set the text in some rows (likely) you need to set or clear it in all rows, or text from rows you set will leak through to cells you don't.

With storyboard prototypes

With storyboards, though, the storyboard and table view handle the initial cell creation! This is brilliant stuff. You map out your cell prototypes directly in the tableview when using storyboards, and Cocoa Touch will do the initial creation for you.

Instead, you get this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SearchResultCell"];
    // You'll always have a cell now!

    // Per row setup here.

    return cell;
}

You're responsible for all the same per row setup as before, but you shouldn't need to write code to build your initial empty cell, either inline or in its own subclass.

As Ian notes below, you can still use the old approach. Just make sure not to include a cell prototype in the storyboard for the identifier you specify. The view controller won't be able to build your cell from the cell prototype, dequeueReusableCellWithIdentifier will return nil, and you'll be exactly where you were before.

like image 161
Steven Fisher Avatar answered Dec 18 '22 14:12

Steven Fisher