Ios UITableViewCell内容在单独重新加载单元格时闪烁

Ios UITableViewCell内容在单独重新加载单元格时闪烁,ios,objective-c,performance,uitableview,asyncdisplaykit,Ios,Objective C,Performance,Uitableview,Asyncdisplaykit,我有一个链接到NSFetchedResultController的表视图(即加载数据和跟踪数据更改绑定到FRC) 我没有在我的单元格中使用AutoLayout(因为它在iOS 8中引入了巨大的性能下降)。我正在单元格中手动布局单元格内容(使用-(void)layoutSubviews)。另外,行的高度是基于内容计算的,并且被正确地缓存/失效 如果与“我的数据”相关的任何条件发生更改,相关单元格将单独更新(通过-(void)controllerWillChangeContent:…通过-(void

我有一个链接到
NSFetchedResultController
的表视图(即加载数据和跟踪数据更改绑定到FRC)

我没有在我的单元格中使用
AutoLayout
(因为它在iOS 8中引入了巨大的性能下降)。我正在单元格中手动布局单元格内容(使用
-(void)layoutSubviews
)。另外,行的高度是基于内容计算的,并且被正确地缓存/失效

如果与“我的数据”相关的任何条件发生更改,相关单元格将单独更新(通过
-(void)controllerWillChangeContent:…
通过
-(void)controllerDidChangeContent:…
代理方法实现)行更新的动画为:
UITableViewRowAnimationNone

这里的问题是,我的细胞有透明的背景,在
[self.tableView reloadRowsAtIndexPaths:…]期间,我可以看到一些视觉噪音(很可能是实际细胞垂直拉伸,我不能肯定,因为它们确实是短暂的)

我试了很多东西都没有用

以下是我尝试过的不起作用的东西:

  • 实现
    -(CGFloat)tableView:(UITableView*)tableView estimatedheightforrowatinexpath:(nsindepath*)indepath
    ,返回估计高度的准确值
  • 设置self.tableView.rowHeight=UITableViewAutomaticDimension,帮助很大,但无法修复它
  • [self.tableView beginUpdates]时禁用动画并在
    [self.tableView endUpdates]之后启用
  • -(void)tableView:(UITableView*)tableView didendisplayingcell:(UITableViewCell*)单元格中的单元格内容中删除所有子视图,用于rowatinexpath:(NSIndexPath*)indexath
有点帮助的事情:

  • 使单元格不透明(即为单元格设置背景色)。奇怪的是,这些工件似乎在实际的单元格内容下
更多信息
  • 我的大多数单元格内容都是来自(ASTextNode、ASImageNode)的节点,但用它们的
    UIKit
    对应项替换它们并不能解决问题
  • 我所有的视觉更新都发生在主线程上。我总是确保这一点
  • 这个问题并不普遍,但往往存在。如果有帮助的话,在插入第二个细胞后,这种情况似乎发生得更多
  • 将方法
    -(void)layoutSubviews
    记录在“我的单元格”中表明,具有更新条件的单元格在每次更新时会连续重新加载3次,而其他单元格只更新一次。我没有强迫任何<代码>[细胞布局需要]
    [单元格设置需要设置]任何地方
  • 使用
    [self.tableView reloadData]重新加载整个表视图不是我的选项
其他更多信息
  • 使细胞不透明导致细胞只被布置一次!奇怪
最后,很抱歉,我不能共享任何实际的代码,因为这不是一个测试项目,而且实现的复杂性使得任何代码共享都是徒劳的,除非作为一个整体来理解


谢谢您的时间。

如果有人遇到同样的问题:

如果您正在计算单元格高度及其元素,并且依赖于
nsindepath
查询任何数据或条件,请始终检查索引路径是否有效(而不是
nil
)。大多数返回索引路径的
UITableView
方法(例如
-(nsindepath*)indexPathForCell:…
等)可能返回
nil
值,并将使您陷入调试视图的漩涡

在我的例子中,我有一个方法来确定我的单元格是否应该有一个标题,为此我检查了它是第一个单元格还是自上一个单元格以来条件发生了变化。问题是
indexPath.row==0
即使索引路径实际上是
nil
(这是Objective-C中的概念问题,其中
nil
为0)。所以有一小会儿,我的细胞会认为它有一个标题


我觉得不检查
nil
索引路径有点愚蠢,但我认为有一天共享它可能会对某人有所帮助。

我也面临着同样的问题,即在使用reloadRowsAtIndexPath时闪烁UITableViewCell,所以我所做的是-

     [UIView setAnimationsEnabled:NO];
     [self.tableView beginUpdates];

     [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
                                               withRowAnimation:UITableViewRowAnimationNone];
     [self.tableView endUpdates];
     [UIView setAnimationsEnabled:YES];

当重新加载单元格时,上面的代码片段在单元格上没有动画。

在swift am中使用此选项,可以减少闪烁

let visibleIndexs = self.ContentTableview.indexPathsForVisibleRows! as NSArray
        print(visibleIndexs)
        for indx in visibleIndexs {
            if self.imgDownloadedIndexs!.containsObject(indx) {
                  UIView.setAnimationsEnabled(false)
                self.ContentTableview.beginUpdates()
                self.ContentTableview.reloadRowsAtIndexPaths([indx as! NSIndexPath], withRowAnimation:.None)
                self.ContentTableview.endUpdates()
                 UIView.setAnimationsEnabled(true)
                self.imgDownloadedIndexs?.removeObject(indx)

            }

是的,您可以使用
perform而不使用动画
(Swift版本)从@Sandy的答案中获得类似的结果


删除rowHeightAtIndexPath方法将解决此问题。确保已在故事板中为表格单元格设置了固定高度。

表格视图自定义单元格不可点击且闪烁。这是因为细胞动画。添加以下代码后,该单元格可进行录制,工作正常。 这种情况通常发生,也可能在运行UITestCase时发生

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   UIView.performWithoutAnimation {
      self.tableView.reloadRows(at: [indexPath], with: .none)
  }
return cell
}

你需要重新加载单元格而不是仅仅更新内容吗?更新内容似乎有点离题。以下内容更改是我避免的事情。与其更新内容(顺便说一句,可能需要重新加载表格视图以调整单元格高度),还不如更新内容,这与主题完全一样。。。调整单元格大小也不需要重新加载。尝试更新单元格,而不是重新加载。好吧,我似乎误解了你的意思。想详细说明一下吗?同样重要的是:数据更新后,内容高度可能会发生变化。亲爱的@Sandy,我知道上述解决方案,但不幸的是,我的表视图收到的更新频率更高,并且与其他类型的更新(插入、删除、移动)混合在一起,我不想丢失其他动画。另外,我的问题与动画本身无关,这是我的错误。比
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   UIView.performWithoutAnimation {
      self.tableView.reloadRows(at: [indexPath], with: .none)
  }
return cell
}