在UITableView中滚动后混合的项目

时间:2010-04-13 13:12:34

标签: iphone cocoa-touch

当我滚动我的UITableView时,细胞变得混乱。 我做错了什么?

这是我的方法:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
    [cell insertSubview:[itemArray objectAtIndex:indexPath.row] atIndex:indexPath.row]; 
    return cell;
}

更新

现在可以使用cell.contentView,但现在当我选择一个项目时,所选项目将覆盖不同单元格的内容......

2 个答案:

答案 0 :(得分:8)

TechZen的建议是正确的。从你的代码中可以清楚地看出你误解了insertSubview:atIndex。我怀疑您可能还需要更好地了解tableView:cellForRowAtIndexPath:何时执行和不调用。

不幸的是,你在这里得到了sagar的一些不好的建议,这可能只会让你更加困惑,特别是因为它最初可能会起作用,但它会扼杀你的滚动性能和内存使用量。为了他和你的利益,让我试着澄清tableView:cellForRowAtIndexPath:和重用标识符概念。

理解tableView:cellForRowAtIndexPath:和重用标识符的关键是要理解构建UITableViewCell是昂贵的。考虑您需要做的所有事情:

  1. 分配单元格
  2. 分配单元格的子视图。
  3. 定义单元格中子视图的布局。
  4. 将子视图添加到单元格。
  5. 配置子视图的属性,例如字体大小,颜色,文本换行,调整大小行为等。
  6. 配置单元格的属性,例如附件图像等。
  7. 定义您希望单元格显示的特定文本和/或图像。
  8. 当我们创建表时,我们通常希望单元具有相同的基本配置。它们通常具有相同数量的子视图,在相同的位置,使用相同的字体等。事实上,通常需要从一个单元格到下一个单元格的唯一不同的是上面列表中的项目7,文本和单元格显示的图像。

    第一步到第六步是非常昂贵的(特别是内存分配),所以如果我们为我们创建的每个单元格执行这些步骤,它会杀死我们的滚动性能,只会在滚动屏幕时抛出该单元格。如果我们可以在滚动屏幕时保存单元格,然后只是调整其内容并将其重新用于我们需要显示的下一个单元格,那会更好。

    Apple认识到需要进行这种单元重用优化,因此他们为UITableView构建了一种机制。当一个单元格滚动离开屏幕时,UITableView不会将其丢弃。相反,它会查看单元的重用标识符字符串,并将单元格放入与该标识符关联的特殊缓冲区中。下次调用dequeueReusableCellWithIdentifier:使用相同的标识符时,UITableView会将单元格从其缓冲区中拉出并将其交还给您以供重用。此单元格仍具有所有相同的子视图,与之前的配置相同,因此您需要做的就是在列表中的第7步。只需更新单元格的文本和/或图像,即可开始使用。

    正确使用此机制时,您只需为每个可见行分配一个单元格,再为缓冲区分配一个单元格。无论你的表中有多少行,你的内存使用率都会保持低水平,你的滚动就像黄油一样顺畅。

    Sagar建议您为每一行使用不同的重用标识符。希望你能明白为什么这是一个坏主意。当每个单元格滚动离开屏幕时,表格视图将查看单元格的标识符,看它是唯一的,并为该特定行创建新的缓冲区。如果滚动10,000行,表视图最终会有10,000个缓冲区,每个缓冲区专用于一个单元格。当您创建10,000个单元格对象时,您的滚动会不必要地慢,并且在您到达表格底部之前,您的应用程序可能会耗尽内存。

    所以请继续保留您的公共小区标识符。在if (cell == nil) { }块内,放置所有单元格通用的设置代码。在该块下面,只放置填充每行唯一内容的代码。要访问要在每行中更改其内容的自定义子视图,可以使用 - [UIView viewWithTag:],或者更好的是,创建UITableViewCell的子类,并将自定义子视图公开为子类的属性。

答案 1 :(得分:1)

我认为您的问题在于您将行逻辑应用于单元格内的视图层次结构而不是单元格本身。

这一行:

[cell insertSubview:[itemArray objectAtIndex:indexPath.row] atIndex:indexPath.row];

从数组中获取视图,并将其添加到 单元格现有子视图堆栈 的特定index.row处的单元格子视图中。它没有做任何事情来确保正确的视图插入适当的单元格本身。如果您从未从上一次迭代中删除视图,您将只看到所有这些视图在各个重用的单元格中堆叠。

至少,您需要删除之前添加的所有单元格子视图,然后再添加最多的子视图。您还应该只将子视图添加到单元格的contentView视图中,而不是单元格本身。

所以:

[[cell.contentView.subviews objectAtIndex:0] removeFromSuperview];
[cell.contentView addSubview:[itemArray objectAtIndex:indexPath.row]];