在 fetchedResultsController 委托方法中插入行时崩溃 (iOS)

Crash when inserting row in fetchedResultsController delegate method (iOS)

我使用以下方法在创建新实体时更新我的​​ tableView,使用 fetchedResultsController 委托:

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .insert:
        //Crash here
        self.tableView.insertRows(at: [newIndexPath!], with: .automatic)
    default:
        print("default")
    }
}

这有效,但有时我会遇到以下崩溃:

 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. 

The number of rows contained in an existing section after the update (6) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). *** First throw call stack:

我正在使用 fetchedResultsController。我做了一些研究,答案声称要更新 numberOfRowsInSection,但我将该部分中的行数设置为 fetchedResultController 部分中的对象数。我尝试在 insertingRows 之后和之前调用 reloadData() 但这并不能解决问题。这是我的 numberOfRowsInSection 方法:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if let sections = fetchedResultsController.sections {
        let currentSection = sections[section]
        return currentSection.numberOfObjects
    }
    return 0
}

还有我的 fetchedResultsController:

lazy var fetchedResultsController: NSFetchedResultsController<Project> = {

    let userFetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Project")
    let coreDataStack = CoreDataStack.default()
    let managedContext = coreDataStack?.managedObjectContext

    let primarySortDescriptor = NSSortDescriptor(key: "dateCreated", ascending: false)
    userFetchRequest.sortDescriptors = [primarySortDescriptor]

        let frc = NSFetchedResultsController(
        fetchRequest: userFetchRequest,
        managedObjectContext: managedContext!,
        sectionNameKeyPath: nil,
        cacheName: nil)

    frc.delegate = self

    return frc as! NSFetchedResultsController<Project>
}()

//解决方案:
正如 Zepar 所提到的,这就是我必须做的来解决这个问题。

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

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

您忘记通知 tableView 内容已开始更新:

[self.tableView beginUpdates]; 

[self.tableView endUpdates]; 

修改的段数和行数必须和抓取的一致。

查看文档,还有一个示例: https://developer.apple.com/reference/coredata/nsfetchedresultscontrollerdelegate