NSFetchedResultsController
Car
(subclass of NSManagedObject
that matches the NSFetchedResultsController
's predicate)NSFetchedResultsControllerDelegate
but the problem is model is updated and I need the table view to match it.NSFetchedResultsControllerDelegate
detects model changes and I can update using the delegate methods.Refer: https://developer.apple.com/documentation/coredata/nsfetchedresultscontrollerdelegate
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).'
Thanks to @Jake and @pbasdf, their suggestions helped my identify and rectify the problem.
I am answering for completeness.
I had multiple sections in my table view and I was inserting row into the wrong section. As a result the table view row count in the relevant section wasn't changing when the model had changed.
I feel it is better to transform the results into an array and use the array as the data source instead of the NSFetchedResultsController
for user driven updates.
When user inserts / deletes / moves rows UITableViewDataSource
methods are invoked:
tableView(_:commit:forRowAt:)
will be invokedtableView(_:moveRowAt:to:)
would be invokedUpdating core data will cause NSFetchedResultsControllerDelegate
to be invoked
controller(_:didChange:at:for:newIndexPath:)
do the following:
controllerDidChangeContent(_:)
invoke tableView.reloadData()
after a delay of 0.5 seconds.When the user moved the row on iOS 11.2
(using NSFetchedResultsController
) I did encounter the following warning:
UITableView internal inconsistency: _visibleRows and _visibleCells must be of same length. _visibleRows
I didn't know how to resolve it, so sticking with the array implementation for now.