NSFetchedResultsController - 用户驱动的更改
NSFetchedResultsController - User Driven Changes
概览
- 我有一个
NSFetchedResultsController
- 用户将能够添加新记录(table 在编辑模式下查看)
- 当用户点击添加按钮时,我能够检测到该事件并创建一个新的
Car
(与 NSFetchedResultsController
的谓词相匹配的 NSManagedObject
的子类)
问题:
- 如何在用户启动操作时在 table 视图中插入新行?
- 根据我当前的实施,应用程序崩溃了。崩溃消息如下。
- 如何准确检测模型更改何时生效? (根据崩溃消息,我觉得我插入行太早了)
注:
- 我知道
NSFetchedResultsControllerDelegate
检测到模型更改,但问题是模型已更新,我需要 table 视图来匹配它。
- 通常
NSFetchedResultsControllerDelegate
检测模型更改,我可以使用委托方法进行更新。
- 我的问题是,由于用户添加行,模型首先更新,然后 table 视图必须根据它进行调整。
参考: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
我不知道如何解决它,所以现在坚持使用数组实现。
概览
- 我有一个
NSFetchedResultsController
- 用户将能够添加新记录(table 在编辑模式下查看)
- 当用户点击添加按钮时,我能够检测到该事件并创建一个新的
Car
(与NSFetchedResultsController
的谓词相匹配的NSManagedObject
的子类)
问题:
- 如何在用户启动操作时在 table 视图中插入新行?
- 根据我当前的实施,应用程序崩溃了。崩溃消息如下。
- 如何准确检测模型更改何时生效? (根据崩溃消息,我觉得我插入行太早了)
注:
- 我知道
NSFetchedResultsControllerDelegate
检测到模型更改,但问题是模型已更新,我需要 table 视图来匹配它。 - 通常
NSFetchedResultsControllerDelegate
检测模型更改,我可以使用委托方法进行更新。 - 我的问题是,由于用户添加行,模型首先更新,然后 table 视图必须根据它进行调整。
参考: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
我不知道如何解决它,所以现在坚持使用数组实现。