Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force UITableView to dump all reusable cells

I have a UITableView where I have the backgroud color set via

UIView *myView = [[UIView alloc] init];
if ((indexPath.row % 2) == 0)
    myView.backgroundColor = [UIColor greenColor];
else
    myView.backgroundColor = [UIColor whiteColor];

cell.backgroundView = myView;
[myView release];

The problem I find is that when I edit a table (via setEditing:YES...) some cells of the same color invariable are next to each other. How do I force UITableView to fully redraw. reloadData is not doing a great job.

Is there are deep-cleaning redraw?

like image 871
John Smith Avatar asked Jul 07 '10 18:07

John Smith


3 Answers

I had this issue before so I'll share with you how I solved it:

You can use a boolean flag (say it's called needsRefresh) to control the behavior of cell creation in -cellForRowAtIndexPath:

An example:

- (UITableViewCell*) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath {
    UITableViewCell *cell = [tableView dequeueResuableCellWithIdentifier:SOME_ID];
    if(!cell || needsRefresh) {
       cell = [[[UITableViewCell alloc] init....] autorelease];
    }
    //.....
    return cell;
}

So, when you need a hard reload, set the needsRefresh flag to YES. Simple as a pimple.

like image 58
Jacob Relkin Avatar answered Nov 20 '22 23:11

Jacob Relkin


For me the accepted answer didn't really work since I had no idea when to set the needsRefresh back to YES.

What worked for me was:

 - (UITableViewCell*) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath {
    UITableViewCell *cell = [tableView dequeueResuableCellWithIdentifier:customCellIdentifier];
    if(nil == cell) {
        cell = [[UITableViewCell alloc]  initWithStyle:UITableViewCellStyleDefault
                                       reuseIdentifier:customCellIdentifier];
    }
    //.....
    return cell;
}

And then you change the customCellIdentifier value whenever you need to. This way the cells are also still reusable if you switch back to the original cell identifier.

like image 3
Roland Keesom Avatar answered Nov 20 '22 23:11

Roland Keesom


The accepted method seems dirty, it just makes a bunch of new cells that are stored along with the bad ones. Here are a couple of solutions depending on your situation:

1. first, for the situation described in the question you should not dump your cells and create new views on every cycle. You need to tag your view and then get it back when from the cell when you get a reuse cell:

- (UITableViewCell*) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath*) indexPath {
    UITableViewCell *cell = [tableView dequeueResuableCellWithIdentifier:SOME_ID];
    if(!cell) {
       cell = [[UITableViewCell alloc] init];

         UIView *myView = [[UIView alloc] init];    
        cell.backgroundView = myView;

        [myView setTag:5]; //<------
    }

    UIView *myView =  [cell viewWithTag:5];  //<------
    if ((indexPath.row % 2) == 0)
        myView.backgroundColor = [UIColor greenColor];
    else
        myView.backgroundColor = [UIColor whiteColor];
    return cell;
}

//then just reload the tableview.

2. ...or even better, why not just use the cell backgrouncolor and update that without creating a view.

3. A sure way to really clear out old cached cells it to simply recreate the UITableView object.

4. In most cases you dont need to destroy these cells, just keep track of your elements and update them after getting the reusable cell.You can tag all your elements, keep a array reference to them, find them thought the view hierarchy... Im sure theres a bunch of other ways.

5. heres a one liner to directly purge all cells, although not best practice to mess with the internals of objects like this as they might change in future versions:

[(NSMutableDictionary*)[tableview valueForKey:@"_reusableTableCells" ] removeAllObjects];
like image 1
Andres Canella Avatar answered Nov 20 '22 23:11

Andres Canella