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

我在 FetchedResultsController 上面临 CoreData 崩溃。

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

注意:崩溃很少发生。

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

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 代表中。

【问题讨论】:

    标签: ios swift core-data nsfetchedresultscontroller


    【解决方案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() 中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多