What can cause mergeChangesFromContextDidSaveNotification not to merge / cancel invalid objects that have been updated?

[EDIT: simplified version of the question]

  • mainMOC is the main context of the managed entity.

  • editorMOC is a managed object context created in editorViewController with an undo manager, so the user can edit one managed object

  • after editorMOC saves mainMOC updates the updated managed entity in the notification handler for NSManagedObjectContextDidSaveNotification

  • In the save handler, if I use [mainMOC refreshObject:obj mergeChanges:YES] , updates for the object are not reflected in mainMOC after the update. If I use [mainMOC refreshObject:obj mergeChanges:NO] , the object is invalid and the next time it fails, the changes are reflected in the data downloaded from the repository.

QUESTION: Why does the object not reflect the update when specifying mergeChanges:YES ?

[ORIGINAL QUESTION]

I have a basic data-based application with several contexts of managed objects. The application is complex and proprietary, so I can’t just pass the code directly from the application. I created a simple test application trying to reproduce my problem, but the test application does not detect the problem. I could not find the logical difference between the implementations. I apologize for not sending the sample code, I suppose I explained its implementation below. If something is unclear, ask in the comments and I will do my best to clarify.

Here is my situation. Everything described below is done in the main thread.

  • The application has a primary managed object context called mainMOC , accessed by the main thread and used with NSFetchedResultsControllers to display data in various table views.

  • I have a controller view editorViewController that allows me to edit an existing object of a specific object. This view manager creates its own managed object context called editorMOC using the same persistent repository coordinator with the undo manager, so changes can be discarded or saved when the editor is canceled.

  • editorViewController oversees NSManagedObjectContextDidSaveNotification . When this notification occurs, the notification handler calls [_mainMOC mergeChangesFromContextDidSaveNotification:notification] to merge the changes with editorMOC into mainMOC .

  • A table view controller that uses the NSFetchedResultsController handles controller delegate messages.

I added the NSLog output to see what happens in all of the above steps, and I checked the following:

  • I see that the object is modified and saved in the editor.
  • I see that NSManagedObjectContextDidSaveNotification is called and the updated object is enabled.
  • I see that the resulting result controller is receiving the controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: protocol message.
  • I see that mainMOC not reflective of updates, and that the updated object was not invalidated by mergeChangesFromContextDidSaveNotification:
  • If I leave and restart the application, updates have been fixed

For reference, both my main application and the test application implement the above functions, but the test application shows that the updates are merged correctly, and the main application does not work.

I am looking for suggestions about what could lead to the fact that mergeChangesFromContextDidSaveNotification: will not be able to successfully merge and / or invalidate the updated object.

Thanks!

+7
source share
4 answers

In an attempt to take something, even if I don’t have a final solution, that’s what I did to solve this problem, and the problem seems to be solved.

I believe this is a cache issue with NSFetchedResultsController. Since then, I have simplified this code and made sure that each NSFetchedResultsController uses its own cache. I managed to remove the "refreshObject" call and it seems that everything is working correctly.

0
source

The result controller does not receive the delegate message controller:didChangeObject:atIndexPath:forChangeType:newIndexPath: Instead, it sends it to the delegate in response to a change in context. If this delegated message is sent and contains the corresponding object, then the main context is aware of the changes.

If so, then your error will most likely be in the code interacting with the selected result controller and table view. Something is preventing the correct appearance of the object.

+2
source

I had a problem due to which mergeChangesFromContextDidSaveNotification did not work. I created a new NSPersistentStoreCoordinator for each new NSManagedObjectContext. When I shared NSPsistentStoreCoordinator between all MOCs, mergeChangesFromContextDidSaveNotification works fine. Also, make sure that mergeChangesFromContextDidSaveNotification is called on the thread that owns the MOC.

From my research, it was safe to share an NSPersistentStoreCoordinator between threads for use with NSManagedObjectContext. NSManagedObjectContext will block persistent storage as needed.

+2
source

One possible answer: you have a third MOC that you did not know about, was / was forgotten. (It happened to me.)

I had

  • mainMOC
  • editorMOC
  • viewerMOC , which happened by accident with an erroneous subclass - it should have looked at the main MOC, but instead created its own and looked at the frozen state. The link "check for editing" went in a different direction, since in this scenario he had to be an "editor".
  • the notification correctly calls the callback, and the data merges correctly in the main MOC (which I could say because the data was correct on restarting).

Note: refreshObject:mergeChanges: not required. this is what I tried too when it didn't work, but merging a notification should take care of all the objects for you.

 - (void)twinStackUpdated:(NSNotification *)notification { [[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification]; } 

not sure if that was your problem, but it might be some, so it is.

0
source

All Articles