mitnosirrag
mitnosirrag

Reputation: 163

UITableViewCell is redrawing on dequeue

My setup

I have a UITableViewCell that is in my main storyboard in a UITableViewController. It gets populated with some JSON data pulled from a REST API that will cause each cell to be a variable height. There are UIImageViews, UILabels all of different heights and styles, think Instagram-esque.

My problem

When I scroll to maybe the 5th or 6th cell, then go back up, they start redrawing and overlapping, so text gets mixed, lines get redrawn, etc.

What I've tried

This seems like a common problem on SO, so I've tried several posted solutions. It seems like my issue is probably the same problem as others face, which is, I am calling addSubview on my cell every time it dequeues, but I've tried checking to see if the cell already exists. I came across another post somewhere (sorry, I can't remember where), that suggests that because I am creating this in the storyboard, it is already initialized and if ( !cell ) will already return false, so I don't know how to prevent it from redrawing.

When I try removing the cell from the storyboard, and creating it programmatically, I get an error saying it can't find a cell with my identifier @"Cell".

I've also tried someone's solution of removing all subviews when I dequeue, so I used:

for ( UIView *view in cell.contentView.subviews ) {
     if ([view isKindOfClass:[UIView class]]) {
         [view removeFromSuperview];
     }
}

and it doesn't find anything.

Upvotes: 2

Views: 642

Answers (4)

ShahiM
ShahiM

Reputation: 3268

The most efficient way to manage this is to subclass UITableViewCell and adding all your required Views as properties. So now when a cell comes up for "recycling", you know where to find the old views, like :

[cell.myTextLabel setText:@""];

aaaand you're done.

UPDATE creating a subclass makes sense if you have only a small number of "TYPES" of cells. create a subclass for each. How much complicated it gets depends on your specific scenario. But i've done it and found it to be the most effective method.

UPDATE 2 or you could make multiple cells in the storyboard, and dequeue the appropriate one based on the data source, save all the coding.

Upvotes: 0

Britto Thomas
Britto Thomas

Reputation: 2120

Try to add a new method in your cell class to reset cell to its default style and call this method after dequeueCell.

Upvotes: 0

Nicolas Buquet
Nicolas Buquet

Reputation: 3955

When you add your subview after dequeueing uour cell, give a tag to your subview. This way, when you dequeue a cell, you can first check for the presence of a subview with your tag, and if it exists, remove it before adding your new view:

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
    // try to dequeue a cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<yourCellIdentifier>];

    if( !cell )
    {
        // create a new cell if necessary
    }

    static int _myViewTag = 1000987 // give it a high int : low value are used by the system in cells

    UIView *v = cell.contentView viewWithTag:_myViewTag];

    if( v ) // subview with such tag already exists, so remove it.
        [v removeFromSuperview];

    // now add your new subview
    [cell.contentView addSubview:<yourView>];

    // adjust height of cell to your view.
    ...
}

Upvotes: 0

Dave Batton
Dave Batton

Reputation: 8845

@rdelmar's comment is correct. You shouldn't do what you're doing. Might work, but it's bad form and you don't want to get into bad habits.

First, take advantage of object oriented programming. A cell should be able to configure itself based on the data you ask it to display. The table view shouldn't be designing the cell.

UITableViewCells need to be optimized for speed. Creating and adding subviews is a slow process. It's OK to do it once, but the cell will be reused (a system optimization) and you should just reuse the existing views that were added the first time the cell was created.

For example, you can hide subviews if they're not needed. You might want to do this in -prepareForReuse. You can move them around in -layoutSubviews. Or change the position of subviews in -updateConstraints.

Typically you just want to pass the data to display to the table view cell subclass from the data source (often the view controller). Let the cell do the display work.

Upvotes: 2

Related Questions