Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableViewCell - how to reset content before reusing

There's an annoying bug that I can't fix.

I have a CustomCell, and in it I have a subview that changes it's color according to object's value.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"CustomCell";

    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    if (cell == nil) {        
        cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    MyObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];

    if ([object.redColor isEqualToNumber:[NSNumber numberWithBool:YES]]) {
        cell.colorView.backgroundColor = [UIColor redColor];
    }
    else {
        cell.colorView.backgroundColor = [UIColor clearColor];
    }       

    return cell;
}

This is all working fine except when I delete a row with redColor = YES from the tableview, and I scroll to show rows that was not visible. The first row that becomes visible (first row that reuses the reusable cell) has red color, even though that row is redColor = NO. And if I scroll again and hide the cell and then show it again, color is set to clearColor, the way it should be.

I think this is because it's reusing the cell that has just been deleted. So I'm trying to reset cell's content before reusing. In CustomCell.m

- (void)prepareForReuse {
    [super prepareForReuse];

    self.clearsContextBeforeDrawing = YES;
    self.contentView.clearsContextBeforeDrawing = YES;
    self.colorView.backgroundColor = [UIColor clearColor];
}

But this is not working. Apple Doc says

The table view's delegate in tableView:cellForRowAtIndexPath: should always reset all content when reusing a cell.

What is the proper way to reset content? Do I have to remove subviews from the superview?

Thanks in advance

like image 238
SFF Avatar asked Jul 13 '15 05:07

SFF


People also ask

What is dequeueReusableCell?

dequeueReusableCell(withIdentifier:)Returns a reusable table-view cell object after locating it by its identifier.

When should you start preparing for reuse?

'Preparing for re-use' means checking, cleaning or repairing recovery operations, by which products or components of products that have become waste are prepared so that they can be re-used without any other pre-processing.

What does prepareForReuse do?

prepareForReuse()Prepares a reusable cell for reuse by the table view's delegate.


1 Answers

This seems to work.

I remove the cell's contentView when prepareForReuse in CustomCell.m

- (void)prepareForReuse {
    [super prepareForReuse];

    // Clear contentView
    BOOL hasContentView = [self.subviews containsObject:self.contentView];    
    if (hasContentView) {
        [self.contentView removeFromSuperview];
    }
}

Add it in again in cellForRowAtIndexPath

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    // Cell
    static NSString *cellIdentifier = @"CustomCell";

    CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    if (cell == nil) {        
        cell = [[CustomCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
    }

    // Restore contentView
    BOOL hasContentView = [cell.subviews containsObject:cell.contentView];
    if (!hasContentView) {
        [cell addSubview:cell.contentView];
    }

    // Configure cell
    MyObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];

    if ([object.redColor isEqualToNumber:[NSNumber numberWithBool:YES]]) {
        cell.colorView.backgroundColor = [UIColor redColor];
    }
    else {
        cell.colorView.backgroundColor = [UIColor clearColor];
    }       

    return cell;
}

Hope this will help someone.

like image 136
SFF Avatar answered Oct 03 '22 14:10

SFF