概述
- 我有一个
NSFetchedResultsController
- 用户将能够添加新记录(编辑模式下的表格 View )
- 当用户点击添加按钮时,我能够检测到事件并创建一个新的
Car (NSManagedObject 的子类,与 NSFetchedResultsController 的谓词)
问题:
- 当用户发起操作时,如何在表格 View 中插入新行?
- 根据我当前的实现,应用崩溃了。崩溃消息如下。
- 如何准确检测模型更改何时生效? (根据崩溃消息,我觉得我插入行太早了)
注意:
- 我知道
NSFetchedResultsControllerDelegate 检测到模型更改 ,但问题是模型已更新,我需要表格 View 来匹配它。
- 通常
NSFetchedResultsControllerDelegate 会检测模型更改,我可以使用委托(delegate)方法进行更新。
- 我的问题是,既然用户添加了行,那么首先更新模型,然后表格 View 必须根据它进行调整。
引用: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
}
}
崩溃错误信息:
由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效更新:第 1 节中的行数无效。更新后现有节中包含的行数 (1) 必须等于更新前该节中包含的行数 (1),加上或减去从该节插入或删除的行数(1 插入,0 删除),加上或减去移入或移出该节的行数( 0 移入,0 移出)。'
Best Answer-推荐答案 strong>
感谢@Jake 和@pbasdf,他们的建议帮助我发现并纠正了问题。
我正在回答完整性。
根本原因:
我的表格 View 中有多个部分,我将行插入错误的部分。因此,当模型发生变化时,相关部分中的表格 View 行数并没有发生变化。
接近用户驱动的更新:
1。使用数组
我觉得将结果转换成一个数组并使用数组作为数据源而不是 NSFetchedResultsController 来进行用户驱动的更新会更好。
2。使用 NSFetchedResultsController:
当用户插入/删除/移动行时UITableViewDataSource 方法被调用:
- 当用户插入/删除行时
tableView(_:commit:forRowAt 会被调用
- 当用户移动行时
tableView(_:moveRowAt:to 会被调用
- 为上述方法相应地更新核心数据
更新核心数据会导致NSFetchedResultsControllerDelegate 被调用
- 在
controller(_:didChange:at:for:newIndexPath 中执行以下操作:
- 对于插入 - 添加 indexPaths
- 对于删除 - 删除 indexPaths
- 对于移动 - 什么都不做,因为 UI 已经是最新的(用户已经移动了行),稍后在
controllerDidChangeContent(_ 调用 tableView.reloadData() 延迟 0.5 秒。
注意:
当用户在 iOS 11.2 上移动该行(使用 NSFetchedResultsController )时,我确实遇到了以下警告:
UITableView internal inconsistency: _visibleRows and _visibleCells must be of same length. _visibleRows
我不知道如何解决它,所以暂时坚持使用数组实现。
关于ios - NSFetchedResultsController - 用户驱动的更改,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/49070451/
|