UITableViewCell cellForRowAtIndexPath 首次滚动时调用大量行

Posted

技术标签:

【中文标题】UITableViewCell cellForRowAtIndexPath 首次滚动时调用大量行【英文标题】:UITableViewCell cellForRowAtIndexPath calling large number of rows when first scrolling 【发布时间】:2010-10-27 23:47:42 【问题描述】:

我一直在研究与 UITableView 和 cellForRowAtIndexPath 相关的问题。

我想让用户能够拥有非常多的行,就像 iPhone 上的大型电子邮件列表一样。当我开始创建一个类时,我发现了这个问题,该类将根据需要从数据库中排队和出列记录组,以节省内存。我发现当我的 UITableViewController 加载时,它会为典型的前 10 个索引(0 到 9)调用 cellForRowAtIndexPath。当我在模拟器的黑色外表面区域单击鼠标或尝试使用向上手势在 UITableView 上向下滚动时,就会出现问题。此时,为所有剩余索引调用 cellForRowAtIndexPath。即使有 1000 多个单元格,也会发生这种情况。我试图用只有 100 个索引(没什么花哨的)重新创建一个非常简单的项目。它做的事情完全一样。当我滚动时,它会从位置 10 到 99 调用 cellForRowAtIndexPath。

这是 UITableView 的正常行为吗?有谁知道为什么它调用所有行的效率低下?

我会说,一旦这个初始阶段发生,它似乎就开始正常工作了。我对此感到非常困惑,因为它几乎不可能根据需要创建一个用于排队和取消排队记录的类。

这是我的简单得多的示例项目的代码:

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
    return 1;



// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
 return 100;



// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 


 printf("RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = %d\n", indexPath.row);


    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    

 cell.textLabel.text = @"Example Text";

 return cell;  

控制台:

…… 视图的初始加载 ......

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 0

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 1

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 2

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 3

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 4

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 5

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 6

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 7

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 8

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 9

…… 第一个滚动手势 ......

ootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 11

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 12

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 13

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 14

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 15

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 16

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 17

。 . 我在这里删除了一些以缩短它 . .

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 97

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 98

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 99

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 10

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 11

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 12

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 13

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 14

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 15

RootViewController, -tableView:cellForRowAtIndexPath; // indexPath.row = 16

(gdb)

感谢您的帮助。

埃里克

编辑(后天)--> 今天我想尝试一个真实的设备而不是我的模拟器。我的 iPhone 3GS 没有重现这种奇怪的行为。我相信我机器上的模拟器可能有问题。我打算在时间允许的时候尝试另一个 MAC。

【问题讨论】:

【参考方案1】:

这个问题的原因是我在我的 Mac 上安装了一个名为 Cinch 的应用程序。

Cinch 是一个窗口管理应用程序,它为 Mac OS 添加了一个窗口“捕捉”功能。否则该程序效果很好。每当我使用 cellForRowAtIndex 路径时,我只需要记住禁用 Cinch。

遗憾的是,我不得不重新加载我的整个计算机才能解决这个问题!希望这对其他遇到这种奇怪功能的人有所帮助。

【讨论】:

非常感谢您的回答。我被困在完全相同的问题上,也使用 Cinch。你为我节省了很多浪费的时间。 你是我的英雄!我永远不会想到这一点。非常感谢。 @geekinit 请选择你的答案 哇!非常感谢!有人通知 Cinch 的开发者吗? @Klaas,我在你回复的时候向 Cinch 报告了这件事。他们说他们正在努力。与此同时,我已经养成了在菜单栏中禁用和启用它的习惯。 ://【参考方案2】:

以防万一有些人有同样的奇怪问题并且没有安装像chinch这样的程序:如果您不使用真正单独的单元格标识符,则会发生相同的行为..如果您只使用苹果示例中的标准标识符,那么它就不起作用了。

每次滑动表格视图时,都会有条目旋转。您必须使每个单元格的单元格标识符都是唯一的。例如:

 NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d", indexPath.row];

我花了一段时间才弄明白。所以如果有人在寻找“uitableview uitableviewcell 奇怪的行为行切换触摸幻灯片上的内容”时发现这个线程,他可以检查这个可能的错误源。

【讨论】:

我认为您错过了单元重用机制的全部要点。当一个单元格离开屏幕时,它会进入重用队列,以便可以再次与另一个索引路径一起使用。这样,同一个单元格对象可以通过dequeueReusableCellWithIdentifier 用于多行(出于性能原因)。因此,无需实例化大量单元格,您只需实例化所需数量的单元格,即尽可能多的可见单元格。如果你给每个单元格一个唯一的重用标识符,那么你根本就没有重用你的单元格。 hmm...那么请告诉我,我应该如何用数据填充我的单元格?我在 cellForRowAtIndexPath 方法中执行此操作。我为对应的行创建单元格并添加带有数据的标签。当单元格不在视线范围内时,会分配其他单元格并填充数据。如果用户再次向上滚动到第一个单元格,它将从 dequeueReusableCellWithIdentifier 方法中出列。因此,当再次显示时,每个单元格都会被重复使用。否则你会怎么做?只有一个内容不断变化的单元格对象? 好的,我再次测试了它.. 看来,我错了 - 它现在似乎真的有效。也许我的代码中有其他问题,目前已经消失了.. 这样你就使用了一个只有一行的单元格对象。这样,您需要与表格视图中的行一样多的单元格。单元重用机制允许您重用具有多行的一个单元对象。当一个单元格离开屏幕时,它可以用来显示另一行。如果滚动表格视图时您的行混淆是因为您在重用单元格时没有清除“旧”内容 真的应该删除这个答案。【参考方案3】:
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];
    if (cell == nil) 
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
    

将此 nil 用于重用标识符,使其正常工作

【讨论】:

以上是关于UITableViewCell cellForRowAtIndexPath 首次滚动时调用大量行的主要内容,如果未能解决你的问题,请参考以下文章

使用 UITapGestureRecognizer 检测 UITableViewCell 中 UILabel 的点击事件

如何在横向上调整自定义 UITableView 分隔符并防止消失

TableView 中的 indexPath 比较

reloadData 被调用两次?

numberOfRowsInSection 多次调用但 cellForRowAtIndexPath 从未调用

未调用 alertviewcontroller 中的 tableview 的“cellForRowAtIndexPath”