19

我有点坚持这个......非常感谢任何帮助。我已经花了很多时间调试这个。

我得到UITableView了由NSFetchedResultsController. 在一个单独的视图控制器中,我使用 向 CoreData 插入新记录[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:],保存托管对象上下文并关闭该控制器。很标准的东西。

然后通过以下方式接收托管对象上下文中的更改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,但没有任何改变。然后我将单元格的样式更改为基本(或除自定义之外的任何内容)并且问题消失了 - 立即添加了新单元格。

我已经检查了两倍,并且NSFetchedResultsControllerDelegate只调用了一次回调。如果我忽略它们并做[UITableView reloadSections:withRowAnimation:],没有任何改变——它仍然很慢。

在我看来,默认单元格样式禁用了自动布局,这使得它们非常快。但如果是这样的话——为什么当我按下 时一切都加载得很快UITableViewController

这是该问题的调用跟踪: 堆栈跟踪

所以问题是——这里发生了什么?为什么细胞渲染如此缓慢?

更新 1

我构建了一个非常简单的演示应用程序来说明我遇到的问题。这是来源- https://github.com/antstorm/UITableViewCellPerformanceProblem

尝试添加至少一屏单元格来感受性能问题。

另请注意,直接添加一行(“立即插入!”按钮)不会导致任何缓慢。

4

5 回答 5

16

确实,自动布局会影响性能。但是,在大多数情况下,它并不明显。有一些具有复杂布局的边缘情况,摆脱它会产生有意义的差异,但这不是这里真正的问题。

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

为此,您可以例如self.tableview.window != nil在获取的结果控制器的委托方法中进行检查。然后你只需要添加一个[self.tableview reloadData]toviewWillAppear以便表格视图在出现在屏幕上之前更新它的数据。

希望有帮助。如果有人对这种奇怪的行为有很好的解释,请告诉我:)

于 2013-06-09T19:31:08.047 回答
2

好的,我终于在不牺牲动画的情况下解决了这个问题。UITableViewCell我的解决方案是在禁用 AutoLayout 的单独 Nib 文件中实现's 接口。加载需要更长的时间,您需要自己定位子视图。

这是使其成为可能的代码:

- (void)viewDidLoad {
    [super viewDidLoad];

    ...        

    UINib *rowCellNib = [UINib nibWithNibName:@"RowCell" bundle:nil];
    [self.tableView registerNib:rowCellNib forCellReuseIdentifier:@"ROW_CELL"];
}

当然,您需要一个包含单元格视图的 RowCell.nib 文件。

虽然原始问题没有解决方案(这对我来说显然是一个错误),但我正在使用这个。

于 2013-06-12T14:08:05.263 回答
2

我在 iOS 7 中的 [table reloadData] 中具有相同的性能。在我的情况下,我解决了这个问题,将单元格配置代码从[cell layoutIfNeeded]以下代码替换:

[cell setNeedsUpdateConstraints];
[cell setNeedsLayout];

然后返回单元格。一切似乎都很好。我希望这可以帮助其他有同样问题的人。

于 2015-01-01T01:57:10.123 回答
0

如果您仍想在表格视图单元格中使用自动布局,有一些方法可以使其高效。这是一个多步骤的过程,但是一旦这样做,除了单元格中其他所有内容的布局之外,您还可以让自动布局引擎确定单元格的垂直大小。

您可以在此处找到更多详细信息:在 UITableView 中使用自动布局进行动态单元格布局和可变行高,其中包括一些在 iOS 8 上可以使用的快捷方式。

于 2014-06-06T20:59:06.660 回答
0

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

- (NSString*) reuseIdentifier {

    return self.dynamicReusableIdentifier;
}

self.dynamicReusableIdentifier 字符串的生成基于单元类(ACellSubclass)中定义的静态方法(configureDynamicReuseIdentifier)。tableView:cellForRowAtIndexPath然后选择从

单元格 = [tableView dequeueReusableCellWithIdentifier:[ACellSubclass configureDynamicReuseIdentifier:someData]];

并且重用单元格的静态子视图(标签、图像)在没有任何自动布局更改的情况下更新。

于 2014-07-08T12:45:17.967 回答