TableView Cell 重用和不需要的复选标记 - 这让我很生气

Posted

技术标签:

【中文标题】TableView Cell 重用和不需要的复选标记 - 这让我很生气【英文标题】:TableView Cell reuse and unwanted checkmarks - this is killing me 【发布时间】:2011-09-13 00:04:40 【问题描述】:

Apple 的 ios TableView 和单元重用正在杀死我。我搜索、搜索和研究,但找不到好的文档或好的答案。问题在于,当TableView 重用单元格时,在选定单元格上设置的复选标记(单元格附件)之类的东西会在表格视图中更下方的单元格中重复。我知道,由于内存限制,单元重用是设计使然,但是如果您有一个包含 50 个项目的列表,并且它开始在不需要的地方设置额外的复选标记,这会使整个努力毫无用处。

我要做的就是在我选择的单元格上打勾。我已经尝试过使用我自己的自定义单元格类以及由样板 TableView 类生成的标准单元格,但它总是以相同的方式结束。

Apple 甚至有一个名为 TouchCell 的示例项目,您可以从开发中心下载,该项目应该显示使用左侧带有图像控件的自定义单元格设置复选标记的不同方式。该项目使用字典对象作为数据源而不是可变数组,因此对于每个项目都有一个字符串值和布尔检查值。这个布尔检查值应该设置复选标记,以便它可以跟踪选定的项目。只要您使用 15 个以上的单元格填充 TableView,此示例项目也会显示这种愚蠢的行为。单元格的重用开始设置不需要的复选标记。

我什至尝试过为每个单元格使用真正唯一的单元格标识符。所以不是每个单元格都有类似@“Acell”的东西,我使用了一个静态int,转换为一个字符串,所以单元格得到@“cell1”,@“cell2”等。虽然在测试期间,我可以看到数百个新单元格在哪里在滚动期间生成,即使表格只有 30 个项目。

它确实解决了复选标记重复问题,但我怀疑内存使用率过高。

就好像当前不在表格可视区域中的单元格在滚动回视图时被重新创建。

有没有人想出一个优雅的解决方案来解决这种恼人的行为?

【问题讨论】:

【参考方案1】:

细胞重复使用可能很棘手,但您必须牢记两件事:

为一种类型单元格使用一个标识符 - 仅当您在一个表格视图中使用不同的 UITableViewCell 子类并且您必须依赖时才需要使用多个标识符它们对不同细胞的不同行为 您重用的单元格可以处于任何状态,这意味着您必须重新配置单元格的各个方面 - 尤其是 checkmars/images/text/accessoryViews/accessoryTypes 等等

您需要做的是为您的复选标记状态创建一个存储 - 一个包含布尔值的简单数组(或分别包含布尔 NSNumber 对象的 NSArray )应该可以做到这一点。然后,当您必须创建/重用单元格时,请使用以下逻辑:

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

    static NSString *reuseIdentifier = @"MyCellType";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    if(cell == nil) 
        /* create cell here */
    
    // Configure cell now
    cell.textLabel.text = @"Cell text"; // load from datasource
    if([[stateArray objectAtIndex:indexPath.row] boolValue]) 
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
     else 
        cell.accessoryType = UITableViewCellAccessoryNone;
    
    return cell;

那么你将不得不对水龙头做出反应:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    [stateArray replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:![[stateArray objectAtIndex:indexPath.row] boolValue]]];
    [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

请记住使用NSMutableArray 来存储您的数据;)

【讨论】:

感谢马丁的建议。我会试一试,尽管它看起来确实是 DevCenter 中 TouchCell 项目中代码的变体(苹果代码)。他们使用 Dictionary 类来存储 BOOL 值和单元格文本。它只适用于几个单元格(9 或 10 个),但当单元格被重复使用 20 到 30 个或更多时,它会以同样的方式搞砸......顺便说一句,我今天早些时候尝试通过仪器运行一个测试应用程序,其中我根本不重用单元格,它实际上使用的内存比首选方法少。 (如果我正确理解乐器!)。 我没有仔细查看他们的代码,但很可能它们看起来很相似,因为这是您想要的方式。也许您应该将代码上传到某处并将链接作为评论发布在这里 我只是在制作一个单视图应用程序来尝试您的建议。我将按照您的建议创建两个可变数组,一个用于显示数据(NSString 值),另一个用于 BOOL 状态。 您是否在使用多个部分?...如果没有代码,我认为我们无法为您做更多事情:( 我会发布一些结果,马丁。我只是想写一些代码同时煮一些食物。你不在丹麦吗?

以上是关于TableView Cell 重用和不需要的复选标记 - 这让我很生气的主要内容,如果未能解决你的问题,请参考以下文章

滚动时重复 TableView 上的复选标记

iOS-TableView重用原理和注意点

使附件类型成为选定单元格的复选标记

设置静态表格视图单元格的复选标记

iOS 怎么避免tableview刷新数据错乱

iOS 杂笔-如何解决tableview显示错乱问题