views:

319

answers:

3

I am having a few nagging issues with NSFetchedResultsController and CoreData, any of which I would be very grateful to get help on.

Issue 1 - Updates: I update my store on a background thread which results in certain rows being delete, inserted or updated. The changes are merged into the context on the main thread using the "mergeChangesFromContextDidSaveNotification:" method. Inserts and deletes are updated properly, but updates are not (e.g. the cell label is not updated with the change) although I have confirmed the updates to come through the contextDidSaveNotifcation, exactly like the inserts and deleted. My current workaround is to temporarily change the staleness interval of the context to 0, but this does not seem like the ideal solution.

Issue 2 - Deleting objects: My fetch batch size is 20. If an object is deleted by the background thread which is in the first 20 rows, everything works fine. But if the object is after the first 20 rows and the table is scrolled down, a "CoreData could not fulfill a fault" error is raised. I have tried resaving the context and reperforming the frc fetch - all to no avail. Note: In this scenario, the frc delegate method "didChangeObject...." is not called for the delete - I assume this is because the object in question had not been faulted at that time (as it is was outside the initial fetch range). But for some reason, the context still thinks the object is around, although is has been deleted from the store.

Issue 3 - Deleting sections : When the deletion of a row leads to the deletion of a section, I have gotten the "invalid number of rows in section???" error. I have worked around this by removing the "reloadSection" line from the NSFetchedResultsChangeMove: section and replacing it with "[tableView insertRowsAtIndexPaths...." This seems to work, but once again, I am not sure if this is the best solution.

Any help would be greatly appreciated. Thank you!

+1  A: 

I think all your problems relate to the fetched results controller's cache.

Issue 1 is caused by the FRC using the cached objects (whose IDs have not changed.) When you add or remove an object that changes the IDs and forces an update of the cache but changing the attributes of an object doesn't do so reliably.

Issue 2 is caused by the FRC checking for the object in cache. Most likely, the object has an unfaulted relationship that persist in the cache. When you delete it in the background the FRC tries to fault in the object at the other end of the relationship and cannot.

Issue 3: Same problem. The cache does not reflect the changes.

You really shouldn't use a FRC's cache when some object other than the FRC is modifying the data model. You have two options:

  1. (Preferred) Don't use the cache. When creating the FRC set the cache property to nil.
  2. Clear the cache anytime the background process alters the data model.

Of course, two defeats the purpose of using the cache in the first place.

The cache is only useful if the data is largely static and/or the FRC manages the changes. In any other circumstance, you shouldn't use it because FRC need to check the actual data model repeatedly to ensure that it has a current understanding of the data. It can't rely on the object copies it squirreled away because another input may have changed the real objects.

TechZen
Thank you very much. Indeed, the cache has been responsible for many of my woes. I am left with only 1 issue now - when I save the context after a deletion synced in from the background context, a frc NSFetchedResultsChangeInsert is called and the deleted contact reinserted, despite the merge policy being NSRollbackMergePolicy.
Run Loop
Not setting the staleness interval to 0 fixes the issue described in the above comment, but this once again results in update changes e.g. the cell label name change, not being reflected.
Run Loop
The last issue was in some way related to the fact that i was using a separate persistent store coordinator for the background moc. Using the main psc in conjunction with not using a cache solved all issues.
Run Loop
A: 

Hi,

I'm having a similar situation ...

When my background thread delete an object my tableview isn't updated correctly, the row is still here.

Even if deleted row at indexPath is called ...

Does having multiple delete and insert in the same time is a problem ? or do you have an idea of where this might come from.

here is what i see in the console :

Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. * -[NSMutableArray removeObjectAtIndex:]: index 0 beyond bounds for empty array with userInfo (null)

You can find more information about my problem here

Ptitaw
A: 

Having the same as described in issue: 2.. But disable caching did not help. Does anyone know what to do?

hinderberg
solved it by removing [fetchRequest setFetchBatchSize:20]; and the caching!
hinderberg