NSFetchedResultsController (Core Data) does NOT provide correct data source Table View Controller
I had encountered a challenge recently. I would really appreciate that anyone could provide any support.
The issue: NSFetchedResultsController (Core Data) does NOT provide correct data source Table View Controller.
What I am trying to achieve:
- I am using CloudKit as my main database which stores most of the user data.
- I use Core Data to store the CKRecordID and recordChangeTag locally for updating Table View and Collection View with those stored value as a handle to fetch related CloudKit data.
- I created an NSFetchedResultsController as an instance variable of the Table View Controller to fetch data results as the data source of the Table View.
What works:
- The CloudKit database can save, modify and delete CKRecord via the app.
- Without using Core Data NSFetchedResultsController where only CloudKit and Table View is in the last version of the project, the app can load CloudKit data to feed the Table View as its Data Source via CloudKit convenient API. Data modification and deletion are also working.
What error do I get:
Now I have CloudKit, Core Data, and Table View Controller's instance variable NSFetchedResultsController, when I was trying to add a new object to the Core Data database and insert a new Table View row, the following error is printed in the console and the app crash:
- timicip_APITest_CloudKit_TableView_StoringRecordID[37142:1567814] ***
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 (0) 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).'*
What have I done that does not work:
- I tried to make sure the new object is saved into the Core Data managed persistent store by calling managedObjectContext.save() every time I insert a new data into the database. But even after I had done that, we the table view is trying to fetch data from the NSFetchedResultsController, the NSFetchedResultsController will not provide the correct quantity of its fetched objects in the table view data source method "tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int". And the app crashes. But when I reopen the app, the data that I entered at last open will be shown in the Table View, while when I add a new object to the Table View, it still crashes.
What do I think the direction of the solution:
- I am not sure if the "managedObjectContext.save()" call really save the data, nor am I sure if using the "NSFetchedResultsController.sections![section].numberOfObjects" returns the saved objects.
- Do I need to create a new fetch request from the database by calling "executeFetchRequest:error: on the NSManagedObjectContext" to the results, but if using this method, what's the point of having an NSFetchedResultsController that is specifically designed for Table View.
- Does "insertRowsAtIndexPaths(indexPaths: [NSIndexPath], withRowAnimation animation: UITableViewRowAnimation)" need any support codes to make sure the update of the Table View with corrected indexPath?
Summary:
I would like to know how to overcome the printed error so that I could add a new row into the Table View with Core Data database feeding the right amount of objects from the managedObjectContext.
Solution:
Implement the NSFetchedResultsControllerDelegate, and let it to fully control the CRUD flow for the Table View, rather than calling regular table view row inserting, deleting methods outside of the NSFetchedResultsControllerDelegate' methods, because Core Data's NSFetchedResultsController is acting as the data source.
Thanks a lot
Regards,
张靖元(Jingyuan Knight Zhang)