2

I have the same question problem as described here How to purge a cached UITableViewCell

But my problem can't be solved with "resetting content".

To be precise - I use a custom cell (own class). While running the application it is possible that I have to use a different "cell type". It's the same class - but it has (a lot of) differnt attributes. Of course I could always reset all the things at "PrepareForReuse" but that's not a good idea I guess (there are a lot things to reset).

My idea - I do all these things in the constructor of the cell. And all the rows will use this "type of cell" later. When the (seldom) situation comes that I have to change the look of all rows I create a new instance of this kind of cell with different settings. And now I want to replace the queued cell with this new one.

I tried it with simply calling the constructor with the same cellidentifier (in the hope it will replace the existing one) but that doesn't work.

I also didn't find a "ClearReusableCells" or something like this.

Is there a way to clear the cache - or to remove / replace a specific item?

Manfred

Community
  • 1
  • 1
ManniAT
  • 1,989
  • 2
  • 19
  • 25
  • Checkout my answer to a similar problem: http://stackoverflow.com/questions/2286669/iphone-how-to-purge-a-cached-uitableviewcell/15832337#15832337 – Vladimir Obrizan Apr 05 '13 at 11:11

2 Answers2

3

Create each cell type (even if they use the same cell class) using a different identifier. So if you have 2 cell types, define 2 identifiers and keep them separate.

I'm not sure where your problem is. You have a bunch of cells, with appearance A, then the user takes some action and they need to become appearance B. If you call reloadData or one of the more granular methods, your datasource will be called again for cellForRowAtIndexPath. Just implement this method to segregate the two cell types.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString* identifier = which mode are we in
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier]; // Will return nil if we haven't got this cell
    if( !cell ) {
        // Create different cell type based on the identifier   
    }
    return cell;
}
Steven Canfield
  • 7,312
  • 5
  • 35
  • 28
  • Which does still not solve the problem - when I call tv.DequeueReusabelCell it will return what it does now. My problem is how to get the new cell (no matter if the same or other class) from that call. Setting a new identifier would help - and produce orphans :( – ManniAT Mar 09 '10 at 09:57
  • First of all thank you for your will to help me, and the time you spent witch my question. You'r asking where my problem is: - it's resource usage. I change my mode - and from that moment on a "heavy - no longer used" cell hangs around in the TV-cache. But it seems as if Apple doesn't provide a "clearing mechanism" - so I guess I have to accept this. That means I'll further work with my current solution (which is like you also wrote) a change of the identifier. THANKS again Manfred – ManniAT Mar 10 '10 at 11:10
  • After you return a cell from cellForRowAtIndexPath, it's up to the tableview to manage that memory. The tableView will free it at some point in the future, but it's not your concern (in general). Only worry about objects you have a reference to ;) – Steven Canfield Mar 10 '10 at 15:21
  • Ah, I didn't know that Steven. I always thought if I ever cache a cell it will be there till...app ends. – ManniAT Mar 16 '10 at 10:08
1

Update

This doesn't work. The memory for the cell that is returned from dequeueReusableCellWithIdentifier is never released.

If you initialize a cell with a non-nil reuseIdentifier, then that cell will NOT be freed until the tableView itself is released. This is true even if [[tableView valueForKey:@"reusableTableCells"] removeAllObjects] is called. Unfortunately, the tableView is retaining the cell in some other private member and the only way to free it is by destroying the tableView.

Short Answer

The answer to the title of the question of how to clear the tableView cell cache is that Apple does not provide the "ClearReusableCells" functionality, but it is reasonably easy to implement yourself. Simply track the time that the tableView's cache was last cleared and track the time that the cell was created. A cell is considered to be dirty if it was created before the tableView's last cache refresh time.

Alternatives

  • Steven Canfield's answer - This is a good answer to the specific question, but it does not scale well if there are multiple attributes that can be changed independently of each other. In that case, you can very quickly have lots of 'modes' and that can get unmanageable. Also, with respect to memory usage, it is true that Apple code is responsible for managing the memory, but it is also true that library cannot know when a particular identifier might be needed again, so it will likely end up keeping these cached cells around longer than it needs to.

  • Recreate the tableView - This is a brute force mechanism that is guaranteed to clear the cell cache. Unfortunately, it is usually inconvenient to recreate the tableView.

  • Jake's Dahl's answer from the alternate question - This is a good mechanism for clearing the cache that probably worked at the time it was written, but it relies on some implementations that Apple does not guarantee, and that have, in fact, already changed.

Implementation There are multiple ways of tracking the tableView's cache refresh time and the cell creation time. I've shown a mechanism below that uses subclasses. Of course, for this to work, you need to make sure that the code that instantiates the table and cells instantiates the subclasses.

@interface MyTableView : UITableView
@property(nonatomic,assign) NSTimeInterval cellCacheRefreshTime ;
@end

@interface MyTableViewCell : UITableViewCell
@property(nonatomic,assign) NSTimeInterval creationTime ;
@end


@implemetation MyTableView

-(void) refreshCellCache {
    self.cellCacheRefreshTime = [NSDate timeIntervalSinceReferenceDate];
}

- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier {
    MyTableViewCell *cell = (id)[super dequeueReusableCellWithIdentifier:identifier] ;
    if( cell.creationTime < aTableView.cellCacheRefreshTime ) {
        return nil ; 
    }    
    return cell ; 
}

@end


@implemetation MyTableViewCell

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier] ;
    self.creationTime = [NSDate timeIntervalSinceReferenceDate];
    return self ;
}

@end
Rich Waters
  • 1,567
  • 16
  • 15