CoreData 在插入和删除时崩溃同时发生

Posted

技术标签:

【中文标题】CoreData 在插入和删除时崩溃同时发生【英文标题】:CoreData crashed on insertion and deletion happens simultaneously 【发布时间】:2019-06-19 14:58:58 【问题描述】:

我在 FetchedResultsController 上面临 CoreData 崩溃。

场景:我正在尝试在 FetchedResultsController 上同时插入和删除一些数据。所以,在这段时间里,意外发生了崩溃。

注意:崩溃很少发生。

我尝试了 *** 的一些答案,但没有一个对我有用。所以,解决这个问题会很有帮助。

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 
 
 switch type 
 
 case .insert:
 guard let newIndexPath = newIndexPath  else  return 
 self.tableView.insertRows(at: [newIndexPath], with: rowAnimation)
 
 case .delete:
 guard let indexPath = indexPath else  return 
 self.tableView.deleteRows(at: [indexPath], with: .none)
 
 case .update:
 guard let indexPath = indexPath else  return 
 self.updateRow(atIndexpath: indexPath)
 
 case .move:

 guard let deleteIndexPath = indexPath, let insertIndexPath = newIndexPath, deleteIndexPath == insertIndexPath else 
    return
 
 self.updateRow(atIndexpath: insertIndexPath)
 

崩溃报告:

*** -[AppName.tableView _endCellAnimationsWithContext:] 中的断言失败,/BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKitCore/UIKit-3698.119.2/UITableView.m:1821

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

我对这个问题有了一些线索,它发生在 tableView.endUpdates() 中的 controllerDidChangeContent 代表中。

【问题讨论】:

【参考方案1】:

.move 案例中,您没有移动任何东西。有一个API:

case .move: tableView.moveRow(at: indexPath!, to: newIndexPath!)

强制解包路径是安全的,因为控制器在 .move 情况下发送两个路径以及在其他情况下发送适当的路径。

【讨论】:

我已经尝试过你的答案,但它似乎对我不起作用。我已经更新了我的崩溃报告并添加了一些关于这个问题的线索。那么,你能再检查一次吗? 通常不会发生,但在某些情况下,例如您同时更改属性会影响可能发生的排序【参考方案2】:

根据您提供的崩溃消息,似乎在插入时发生了崩溃,但表视图仍然有旧的行数。

正如 Apple 文档中所写,建议您执行一系列嵌套在 tableView.beginUpdates()tableView.endUpdates() 方法调用之间的表视图更改。

这将允许表视图通过调用来同步数据

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func numberOfSections(in tableView: UITableView) -> Int

方法等

因此,您可以在 NSFetchedResultsControllerDelegate 的方法实现中添加 tableView.beginUpdates(), tableView.endUpdates() 调用

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    tableView.beginUpdates()


func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    tableView.endUpdates()

您也没有正确处理.move 案例。 tableView.moveRow(at: oldIndexPath, to: newIndexPath) 应该被调用

【讨论】:

我们已经添加了 beginUpdates() 和 endUpdates() 但很抱歉我没有包括在这里。另外,我的问题是,只有当我们将单元格从一个地方移动到其他地方时才会调用。 是的,在重新排列表格视图单元格时应该调用 move。另外,如果您不关心动画,您可以在func controller(_ controller: NSFetchedResultsController&lt;NSFetchRequestResult&gt;, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 中调用tableView.reloadData(),并且不会再次发生崩溃 我已经尝试通过插入和删除来改变移动,但它仍然在发生。另外,我更新了我的崩溃报告。你能检查一下吗? 另外,我得到的一个线索是,它发生在 controllerDidChangeContent 委托的 tableView.endUpdates() 中。

以上是关于CoreData 在插入和删除时崩溃同时发生的主要内容,如果未能解决你的问题,请参考以下文章

真机执行CoreData查询Fetch请求时App发生崩溃(模拟器中正常)的原因及解决

真机执行CoreData查询Fetch请求时App发生崩溃(模拟器中正常)的原因及解决

删除coredata列表项时SwiftUI App崩溃EXC_BAD_ACCESS错误

iPhone - 在删除 CoreData 中的对象后尝试保存新对象时应用程序崩溃

从 Core Data 中删除对象和切换视图控制器时崩溃

从核心数据中删除对象 - 崩溃的应用程序