如何清除缓存的UITableViewCell

时间:2010-02-18 06:13:38

标签: ios uitableview reuseidentifier

有没有人就如何清除缓存的UITableViewCell

提出建议

我想用reuseIdentifier缓存这些单元格。但是,有时我需要删除或修改某些表行。我希望在行更改后调用reloadData

现在,dequeueReusableCellWithIdentifier始终返回之前的缓存(过时)条目。如何指示缓存是否陈旧且需要清除?

8 个答案:

答案 0 :(得分:7)

我不确定你为什么要首先清除细胞。每次出列单元格时,都需要重新设置需要显示的数据。缓存只会阻止您每次都必须设置任何不变的属性。但是必须设置正在显示的实际数据,即使之前缓存了单元格。

请注意,对于所有相同类型的单元格,您的重用标识符应该是相同的。如果你正在做一些愚蠢的事情,比如根据有问题的行计算标识符,那么你做错了。

您的代码应该类似于

- (UITableViewCell *)tableView:(UITableView *)view cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *identifier = @"CellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
    if (!cell) {
        // no cached cell, create a new one here
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
        // set any properties that all such cells should share, such as accessory, or text color
    }
    // set data for this particular cell
    cell.textLabel.text = @"foo";
    return cell;
}

在该示例中,请注意我每次都始终为单元格设置数据,并且所有单元格共享相同的标识符。如果您遵循这种模式,您根本没有理由尝试“清除”您的单元格,因为任何旧数据都会被覆盖。如果您有多种类型的单元格,在这种情况下您可能希望使用多个标识符,但每个单元格类型仍然是1个标识符。

答案 1 :(得分:3)

我不知道如何清除缓存,但是,当需要更改行时,我会使用解决方法来处理这种情况。

首先,我不使用静态单元标识符。我要求数据对象生成它(注意[myObject signature],它提供一个描述所有需要属性的唯一字符串):

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    MyObject *myObject = _dataSource[indexPath.row];
    NSString *cellId = [myObject signature];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
        [myObject configureCell:cell];
    }
    [myObject updateCellWithData:cell];
    return cell;
}

[myObject signature]为不同的属性列表提供不同的签名。因此,如果我的对象被更改,我只需调用[self.tableView reloadData],myObject将提供一个新签名,并且该表为其加载一个新单元格。

[myObject configureCell:cell]将所有需要的子视图放入单元格。

[myObject updateCellWithData:cell]使用当前数据更新单元格的子视图。

答案 2 :(得分:3)

while ([tableView dequeueReusableCellWithIdentifier:@"reuseid"]) {}

答案 3 :(得分:2)

我找到了一个非常好的方法。

在.h

//add this
int reloadCells;

在.m

- (void)dumpCache {
    reloadCells = 0;
    [tableView reloadData];
}

-(void)tableView:(UITableView *)tableView cellForRowAtUndexPath:(NSIndexPath *)indexPath {
    static NSString *CellID = @"Cell"
    UITableViewCell *cell = [tableView dequeCellWithReuseIdentifier:CellID];
    if (cell == nil || reloadCells < 12) {
        cell = [[UITableViewCell alloc] initWithFormat:UITableViewCellStyleDefault reuseIdentifier:CellID];
        reloadCells ++;
    }
    cell.textLabel.text = @"My Cell";

return cell;
}

答案 4 :(得分:1)

今天我必须有类似的东西。我有一个图像库,当用户删除它们时,图库需要摆脱最后排队的单元格并用“画廊空”图像替换它。当删除例程完成时,它将'purge'标志设置为YES,然后执行[tableView reloadData]。 cellForRowAtIndexPath中的代码如下所示:

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

    NSString *cellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: cellIdentifier];
    if (purge) {
        cell = nil;
        purge = NO;
    }
    if (cell == nil) {
        //*** Do usual cell stuff
    }
    return cell
}

答案 5 :(得分:1)

我正在编写ObjC(手动引用计数),并发现了一些阻止UITableView和UITableViewCells被释放的奇怪行为,尽管我的内存管理是正确的。 UITableView和UITableViewCell似乎相互保留。是的,我找到了一种方法来强制UITableView及其单元格相互释放(删除缓存的单元格)。

要做到这一点,基本上你要求一个可重复使用的单元格的表视图。表视图将从可重用的单元缓存中删除它。毕竟你告诉那个单元格从它的超级视图中删除。完成。

现在作为一个独立的类......首先,您需要一个包含所有单元格标识符的数组。接下来,实现一个虚拟数据源,让该数据源通过使用&#34; ClearAllCachedCells&#34;重新加载自身来清除UITableView。数据来源:

#import <UIKit/UIKit.h>
@interface ClearAllCachedUITableViewCellsDataSource : NSObject <UITableViewDataSource, UITableViewDelegate>

+(void)clearTableView:(UITableView*)tv
     reuseIdentifiers:(NSArray<NSString*>*)cellIdentifiers
  delegateAfterFinish:(id<UITableViewDelegate>)dg
dataSourceAfterFinish:(id<UITableViewDataSource>)ds;

@end

魔法发生在.m文件中:

#import "ClearAllCachedUITableViewCellsDataSource.h"


@interface ClearAllCachedUITableViewCellsDataSource () {
    BOOL clearing;
}
@property (nonatomic, readonly) UITableView *tv;
@property (nonatomic, readonly) NSArray<NSString*> *identifiers;
@property (nonatomic, readonly) id ds;
@property (nonatomic, readonly) id dg;
@end

@implementation ClearAllCachedUITableViewCellsDataSource

-(void)dealloc {
    NSLog(@"ClearAllCachedUITableViewCellsDataSource (%i) finished", (int)_tv);
    [_tv release];
    [_ds release];
    [_dg release];
    [_identifiers release];
    [super dealloc];
}

-(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
    [self performSelectorOnMainThread:@selector(clear) withObject:nil waitUntilDone:NO];
    NSLog(@"TV (%i): reloading with zero cells", (int)_tv);
    return 0;
}

-(void)clear {
    if (!clearing) {
        clearing = YES;
        for (NSString *ident in self.identifiers) {
            UITableViewCell *cell = [_tv dequeueReusableCellWithIdentifier:ident];
            while (cell) {
                NSLog(@"TV (%i): removing cached cell %@/%i", (int)_tv, ident, (int)cell);
                [cell removeFromSuperview];
                cell = [_tv dequeueReusableCellWithIdentifier:ident];
            }
        }
        self.tv.delegate = self.tv.delegate == self ? self.dg : self.tv.delegate;
        self.tv.dataSource = self.tv.dataSource == self ? self.ds : self.tv.dataSource;
        [self release];
    }
}

+(void)clearTableView:(UITableView*)tv
     reuseIdentifiers:(NSArray<NSString*>*)cellIdentifiers
  delegateAfterFinish:(id<UITableViewDelegate>)dg
dataSourceAfterFinish:(id<UITableViewDataSource>)ds {
    if (tv && cellIdentifiers) {
        NSLog(@"TV (%i): adding request to clear table view", (int)tv);
        ClearAllCachedUITableViewCellsDataSource *cds = [ClearAllCachedUITableViewCellsDataSource new];
        cds->_identifiers = [cellIdentifiers retain];
        cds->_dg = [dg retain];
        cds->_ds = [ds retain];
        cds->_tv = [tv retain];
        cds->clearing = NO;
        tv.dataSource = cds;
        tv.delegate = cds;
        [tv performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
    }
}

@end

答案 6 :(得分:0)

应使用消息prepareForReuse清除以前使用该单元格的旧数据。当单元格出列时,此消息将在从dequeueReusableCellWithIdentifier:返回之前发送到单元格。

答案 7 :(得分:0)

没办法,我想...... 我使用了一种完全不同的方法。我没有依赖UITableView缓存,而是自己构建。通过这种方式,我可以完美控制清除的时间和内容。 像这样......

下式给出:

NSMutableDictionary *_reusableCells;
_reusableCells = [NSMutableDictionary dictionary];

我能做到:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = @"whatever-you-need";

    UITableViewCell *cell = [_reusableCells objectForKey:cellIdentifier];

    if (cell == nil)
    {
        // create a new cell WITHOUT reuse-identifier !!
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
        // store it in my own cache
        [_reusableCells setObject:cell forKey:cellIdentifier];
        /* ...configure the cell... */
    }

    return cell;
}

-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    [_reusableCells removeAllObjects];
}

希望这可能会有所帮助。