UITableView CoreData 断言失败

Posted

技术标签:

【中文标题】UITableView CoreData 断言失败【英文标题】:UITableView CoreData Assertion Failure 【发布时间】:2012-10-05 21:36:44 【问题描述】:

当我的 iPhone 应用程序崩溃时,我在控制台中收到此错误:

*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-2372/UITableView.m:1070

当到达这行代码时它崩溃并给我这个:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller 
    [tableView endUpdates];

关于我的应用的一些细节以及我是如何做到这一点的。我有一个带有表格视图的视图控制器,它显示我的核心数据对象。我有这个视图设置来显示来自两个实体的数据,所以表部分 1 显示来自实体的对象,然后部分 2 显示来自我的第二个实体的对象。

这就是我的问题开始的地方。虽然这已经很好地解决了,但我可以推送我的下一个视图控制器,并将对象添加到我的第一个实体并立即弹出回我的 tableviewcontroller 没有问题。但是,如果我尝试将对象添加到第二个实体,则在返回到我的 tableviewcontroller 时,它会崩溃,如上所述。

我不知道是什么原因造成的,所以我不确定从哪里开始寻找。

来自控制台的一些额外错误信息:

CoreData:错误:严重的应用程序错误。在调用 -controllerDidChangeContent: 期间,从 NSFetchedResultsController 的委托中捕获了异常。无效更新:第 0 节中的行数无效。更新后现有节中包含的行数 (2) 必须等于更新前该节中包含的行数 (2),加上或减去数字从该部分插入或删除的行数(1 插入,0 删除)加上或减去移入或移出该部分的行数(0 移入,0 移出)。与 userInfo (null)

代码:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

    // Return the number of rows in the section.
    NSInteger rows;

    id <NSFetchedResultsSectionInfo> sectionInfoAccounts = [[fetchedResultsControllerAccounts sections] objectAtIndex:0];
    id <NSFetchedResultsSectionInfo> sectionInfoCosts = [[fetchedResultsControllerCosts sections] objectAtIndex:0];

    if (section == 0) rows = [sectionInfoAccounts numberOfObjects];
    else if (section == 1) rows = [sectionInfoCosts numberOfObjects];

    return rows;

【问题讨论】:

Xcode 应该打印出更多关于断言失败的信息。编辑您的帖子以包含它打印的所有内容。 这就是我在控制台中得到的所有内容。 设法获取更多错误信息。检查我的问题。 注意,错误提示“第 0 节中的行数无效”。但是,当我尝试在第 1 节中插入一行时,我只会遇到此崩溃。我没有得到的另一个小混乱,它在某处获得了错误的索引? 即使您只修改了第 1 部分,表格视图仍然可以询问第 0 部分。您的数据源和委托必须准备好返回有关任何部分的正确信息。 【参考方案1】:

您正在为表视图使用 2 个获取的结果控制器:一个 FRC 用于表部分 0,一个 FRC 用于表部分 1。我在这里有点猜测,但可能是错误在

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath

如果为第二个 FRC 调用该函数,则 indexPath/newIndexPath 的节部分为 0(因为 FRC 只有一个节)。但是对应的表节是1。

因此,在调用insertRowsAtIndexPaths:...insertRowsAtIndexPaths:... 等之前,您必须将 FRC 索引路径映射到表视图的索引路径。

以插入事件为例:

NSIndexPath *newIndexPath1 = [NSIndexPath indexPathForRow:newIndexPath.row inSection:1];
[self.tableView insertItemsAtIndexPaths:@[newIndexPath1]];

否则第二个实体的新对象将作为第一个表视图部分的行插入,这会导致不一致异常。

【讨论】:

这实际上很有意义,谢谢。我已将if (controller == fetchedResultsControllerCosts) newIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:1]; 添加到上述方法中,它停止了我看到的错误。但是,现在这会导致在配置单元格时到达Cost *cost = [fetchedResultsControllerCosts objectAtIndexPath:indexPath]; 时出现数组对象越界错误。 原来我只需要更改那里的部分,这次为 0。因为对象在 FRC 的第 0 部分,但在表格的第 1 部分。

以上是关于UITableView CoreData 断言失败的主要内容,如果未能解决你的问题,请参考以下文章

尝试从 UITableView 中删除行时断言失败

UITableView 的“尝试删除部分”断言失败

UITableView _endCellAnimationsWithContext:无故断言失败

断言失败 -[UITableView _endCellAnimationsWithContext]

具有多个 NSFetchedResultsControllers 的 UITableView 导致断言失败

iOS 7 上的 -[UITableView layoutSublayersOfLayer:] 中的断言失败