NSFetchedResultsController - 用户驱动的更改

NSFetchedResultsController - User Driven Changes

概览

问题:

注:

参考:https://developer.apple.com/documentation/coredata/nsfetchedresultscontrollerdelegate

创建 NSFetchedResultsController:

let fetchRequest : NSFetchRequest<Car> = Car.fetchRequest()

fetchRequest.predicate = NSPredicate(format: "color = %@", argumentArray: ["green"])

let orderIDSortDescriptor = NSSortDescriptor(keyPath: \Car.price, ascending: true)

fetchRequest.sortDescriptors = [orderIDSortDescriptor]

fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest,
                                                      managedObjectContext: context,
                                                      sectionNameKeyPath: nil,
                                                      cacheName: nil)

编辑样式

override func tableView(_ tableView: UITableView,
                        editingStyleForRowAt indexPath: IndexPath) -> UITableViewCellEditingStyle {

    let newCarIndex = fetchedResultsController?.fetchedObjects?.count ?? 0

    let editingStyle : UITableViewCellEditingStyle

    switch indexPath.row {

    case newCarIndex:
        editingStyle = .insert

    default:
        break            
    }

    return editingStyle
}

提交用户操作

override func tableView(_ tableView: UITableView,
                        commit editingStyle: UITableViewCellEditingStyle,
                        forRowAt indexPath: IndexPath) {

    switch editingStyle {

    case .insert:
        createGreenCar(at: indexPath) //Creating a new Car with color = Green
        tableView.insertRows(at: [indexPath], with: .automatic) //This causes the app to crash
    default:
        break
    }
}

崩溃错误信息:

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), 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).'

感谢@Jake 和@pbasdf,他们的建议帮助我确定并纠正了问题。

我的回答是为了完整性。

根本原因:

我的 table 视图中有多个部分,我将行插入到错误的部分。因此,当模型更改时,相关部分中的 table 视图行数没有改变。

采用用户驱动的更新:

1。使用数组

我觉得最好将结果转换成一个数组并将该数组用作数据源而不是 NSFetchedResultsController 用于用户驱动的更新。

2。使用 NSFetchedResultsController:

当用户插入/删除/移动行时 UITableViewDataSource 方法被调用:

  • 当用户插入/删除行时tableView(_:commit:forRowAt:)将被调用
  • 当用户移动行时 tableView(_:moveRowAt:to:) 将被调用
  • 为上述方法相应地更新核心数据

更新核心数据将导致 NSFetchedResultsControllerDelegate 被调用

  • controller(_:didChange:at:for:newIndexPath:) 中执行以下操作:
    • 对于插入 - 添加 indexPaths
    • 删除 - 删除 indexPaths
    • 移动 - 什么都不做,因为 UI 已经是最新的(用户已移动行),稍后在 controllerDidChangeContent(_:) 延迟 [=47] 后调用 tableView.reloadData() =]0.5秒.

注:

当用户移动 iOS 11.2 上的行(使用 NSFetchedResultsController)时,我确实遇到了以下警告:

UITableView internal inconsistency: _visibleRows and _visibleCells must be of same length. _visibleRows

我不知道如何解决它,所以现在坚持使用数组实现。