在UITableView中滚动后混合的项目 [英] Items mixed up after scrolling in UITableView

查看:107
本文介绍了在UITableView中滚动后混合的项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在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,但现在当我选择一个项目,所选的一个覆盖了不同的单元格的内容...

解决方案

TechZen在这里的建议是正确的。从代码中可以清楚地看到,你误解了insertSubview:atIndex。我怀疑你可能还需要更好地了解什么时候tableView:cellForRowAtIndexPath:和不调用。



不幸的是你从sagar得到一些不好的建议,这可能只会让你进一步困惑,尤其是因为它可能似乎起初工作,但它会杀死你的滚动性能和内存使用。为了他的利益和你的,让我尝试澄清tableView:cellForRowAtIndexPath:和重用标识符的概念。



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


  1. 分配单元

  2. 分配单元格的子视图。

  3. 定义单元格内的子视图的布局。

  4. 将单元格添加到单元格。

  5. 配置子视图的属性,例如字体大小,颜色,文字换行和调整行为等。

  6. 配置单元格的属性,如附件图片等。

  7. 定义您希望单元格显示的特定文本和/或图片。

我们通常希望单元具有相同的基本配置。他们通常具有相同数量的子视图,在相同的位置,使用相同的字体等。事实上,通常需要从一个单元格到下一个单元格是不同的项目7在上面的列表中,文本和单元格显示的图像。



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



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



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



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



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


When I scroll in my UITableView, the cells become mixed up. What am I doing wrong?

This is my method:

- (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;
}

Update

It now works by using cell.contentView, but now when I select an item, the selected one is overlayed with the content of a different cell...

解决方案

TechZen's advice here is correct. It's clear from your code that you've misunderstood insertSubview:atIndex. I suspect that you probably also need a better understanding of when tableView:cellForRowAtIndexPath: does and doesn't called.

Unfortunately you've gotten some bad advice from sagar here, which may only confuse you further, especially because it may appear to work at first, but it will kill your scrolling performance and memory usage. For his benefit and yours, let me try to clarify tableView:cellForRowAtIndexPath: and the reuse identifier concept.

The key to understanding tableView:cellForRowAtIndexPath: and the reuse identifier is to understand that building a UITableViewCell is expensive. Consider all the things you need to do:

  1. Allocate a cell
  2. Allocate the cell's subviews.
  3. Define the layout of the subviews within the cell.
  4. Add the subviews to the cell.
  5. Configure properties of the subviews such as font sizes, colors, text wrapping, resizing behaviors, etc.
  6. Configure properties of the cell, such as accessory images, etc.
  7. Define the specific text and/or images that you want the cell to display.

When we create a table, we usually want the cells to have the same basic configuration. They'll typically have the same number of subviews, in the same positions, using the same fonts, etc. In fact, the only thing that usually needs to vary from one cell to the next is item 7 in the list above, the text and images displayed by the cell.

Steps one through six are quite expensive (especially the memory allocation), so it would kill our scrolling performance if we were to go through those steps for every cell we created, only to throw that cell away when it scrolls off the screen. It would be better if we could save the cell when it scrolls off the screen, and then just tweak its contents and reuse it for the next cell that we need to display.

Apple recognized the need for this cell reuse optimization, so they built a mechanism for it right into UITableView. When a cell scrolls off the screen, UITableView doesn't throw it away. Instead it looks at the cell's reuse identifier string, and puts the cell into a special buffer associated with that identifier. The next time you call dequeueReusableCellWithIdentifier: with that same identifier, UITableView will pull the cell out of its buffer and hand it back to you for reuse. This cell still has all the same subviews, in the same configuration as before, so all you need to do is step 7 in our list. Simply update the cell's text and/or images, and it's ready to go.

When you use this mechanism correctly, you'll only allocate one cell for each visible row, plus one for the buffer. No matter how many rows you have in your table, your memory usage will stay low, and your scrolling will be as smooth as butter.

Sagar recommended that you use a different reuse identifier for each row. Hopefully you can see why this is a bad idea. When each cell scrolls off the screen, the table view will look at the cell's identifier, see that it's unique, and create a new buffer for that specific row. If you scroll through 10,000 rows, your table view will end up with 10,000 buffers, each dedicated to a single cell. Your scrolling will be unnecessarily slow while you create 10,000 cell objects, and your app will probably run out of memory before you get to the bottom of the table.

So go ahead and keep your common cell identifier. Inside the if (cell == nil) { } block, put all the setup code that would be common for all cells. Beneath that block, put only the code that populates the contents that are unique to each row. To access custom subviews whose contents you want to change per row, you can use -[UIView viewWithTag:], or better yet, create a subclass of UITableViewCell, and expose your custom subviews as properties of your subclass.

这篇关于在UITableView中滚动后混合的项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆