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<NSFetchRequestResult>, 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错误