UITableViewCell与AutoLayout性能不佳

我有点卡住了这个…任何帮助,非常感激。 我已经花了很多时间来debugging。

我已经得到了由NSFetchedResultsController提供的数据源的UITableView 。 在单独的视图控制器中,我使用[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:]向CoreData插入新logging,保存托pipe对象上下文并closures该控制器。 非常标准的东西。

被pipe理的对象上下文的变化然后由NSFetchedResultsController接收:

 - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { [self.tableView beginUpdates]; } - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { [self.tableView endUpdates]; } - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { switch (type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; break; case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; [self.tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone]; break; } } 

这就是问题出现的地方 – 它需要很长的时间(iPhone 4需要3-4秒)才能做到这一点。 而且似乎花费在计算单元格的布局上。

我已经从单元格(包括自定义子类)剥离了所有的东西,只留下了UILabel ,但没有任何改变。 然后我把单元格的样式改成了Basic(或除了Custom之外的任何东西),问题就消失了 – 新的单元格被瞬间添加。

我已经加倍检查和NSFetchedResultsControllerDelegatecallback只被调用一次。 如果我忽略它们并做[UITableView reloadSections:withRowAnimation:] ,没有什么变化 – 它仍然是非常缓慢的。

在我看来,像自动布局被禁用默认单元格样式,这使得他们非常快。 但是,如果是这样的话 – 为什么当我推UITableViewController时候一切都会加载?

以下是该问题的呼叫追踪: 堆栈跟踪

所以问题是 – 这里发生了什么? 为什么细胞呈现得如此缓慢?

更新1

我已经构build了一个非常简单的演示应用程序来说明我遇到的问题。 这里的源代码 – https://github.com/antstorm/UITableViewCellPerformanceProblem

尝试添加至less一个屏幕的单元格,以感受性能问题。

另外请注意,直接添加一行(“现在插入!”button)不会造成缓慢。

自动布局确实可以带来性能的提升。 但是,在大多数情况下,这并不是很明显。 有一些复杂布局的边缘案例,摆脱它会产生有意义的差异,但这不是真正的问题。

我没有一个很好的解释,为什么应用程序的行为是这样的,但至less我有一个解决scheme:如果表视图不在屏幕上,不要做表视图更新。 这导致了这种奇怪的行为。

为此,您可以例如在fetched results controller的委托方法中检查self.tableview.window != nil 。 然后你只需要添加一个[self.tableview reloadData]viewWillAppear这样表格视图就可以在屏幕上更新它的数据。

希望有所帮助。 请,如果有人对这个奇怪的行为有一个很好的解释,请让我知道:)

好吧,我终于解决了这个问题,而不牺牲animation。 我的解决scheme是在禁用AutoLayout的单独的Nib文件中实现UITableViewCell的接口。 加载需要一点点时间,你需要自己定位子视图。

以下是使之成为可能的代码:

 - (void)viewDidLoad { [super viewDidLoad]; ... UINib *rowCellNib = [UINib nibWithNibName:@"RowCell" bundle:nil]; [self.tableView registerNib:rowCellNib forCellReuseIdentifier:@"ROW_CELL"]; } 

当然,你需要一个RowCell.nib文件和你的单元格视图。

虽然没有解决原来的问题(这显然是一个错误),我用这个。

我在iOS 7的[reloadData]中也有相同的性能。在我的例子中,我解决了这个问题,将[cell layoutIfNeeded]的单元configuration代码replace为以下代码:

 [cell setNeedsUpdateConstraints]; [cell setNeedsLayout]; 

然后返回单元格。 Evevthing似乎没问题。 我希望这可以帮助别人也有同样的问题。

如果您仍然希望在表格视图单元格中使用“自动布局”,则可以通过多种方式使其具有高性能。 这是一个多步骤的过程,但是一旦你这样做了,你可以让自动布局引擎确定一个单元格的垂直尺寸以及单元格中其他所有元素的布局。

你可以在这里find更多的细节: 在UITableView中使用自动布局来获得dynamic单元格布局和可变的行高 ,其中包括你可以在iOS 8上使用的一些快捷键。

我在uitableviewcell子类中使用复杂的自动布局有类似的问题。 我的单元格布局取决于来自服务器的数据,但单元格状态的数量限制为六个。 所以每次我从dequeueReusableCellWithIdentifier(创build一个新的单元格)都得到nil时,我为刚刚创build的单元格(self.dynamicReusableIdentifier)设置了一个dynamic/自定义的reuseIdentifier。 在UITableViewCell子类(ACellSubclass)中重写了reuseIdentifier getter:

 - (NSString*) reuseIdentifier { return self.dynamicReusableIdentifier; } 

self.dynamicReusableIdentifierstring的生成基于单元类(ACellSubclass)中定义的静态方法(configureDynamicReuseIdentifier)。 tableView:cellForRowAtIndexPath然后从中返回正确的可重复使用的标识符

cell = [tableView dequeueReusableCellWithIdentifier:[ACellSubclass configureDynamicReuseIdentifier:someData]];

并重新使用的单元格的静态子视图(标签,图像)更新没有任何自动布局更改。