How to ignore changes to mergeChangesFromContextDidSaveNotification in NSManagedObjectContextWillSaveNotification

I use a private managed object context to create some new objects in persistent storage, and then after saving the private MOC, merging them into the main MOC using mergeChangesFromContextDidSaveNotification . This works great and updates the user interface as needed, and NSManagedObjectContextWillSaveNotification is NOT used here for mainMOC here.

Then I make some changes to mainMOC using the user interface and listen to NSManagedObjectContextWillSaveNotification . The notification is published, but it contains not only the changes I made, but also objects that were merged with PrivateMOC using mergeChangesFromContextDidSaveNotification .

Is there a way to ignore changes that have been merged from another context into mainContext with subsequent contextDidChange notifications?

Here is the setup:

 - (void) loadData { privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType]; privateContext.persistentStoreCoordinator = self.mainContext.persistentStoreCoordinator; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextWillSave:) name:NSManagedObjectContextWillSaveNotification object: self.mainContext]; NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:record.recordType inManagedObjectContext: self.privateContext]; // fill in object if ([self.privateContext hasChanges]) { [self savePrivateContextAndMergeWithMainContext: self.privateContext]; } } - (void) savePrivateContextAndMergeWithMainContext: (NSManagedObjectContext *) privateContext { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(privateContextDidChange:) name:NSManagedObjectContextDidSaveNotification object:privateContext]; __block NSError *error = nil; [privateContext performBlockAndWait:^{ NSLog(@"PrivateContext saved"); [privateContext save:&error]; }]; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:privateContext]; if (error) { NSLog(@"error = %@", error); } } - (void) privateContextDidChange: (NSNotification *) notification{ [self.mainContext performBlockAndWait:^{ NSLog(@"merged into mainContext"); [self.mainContext mergeChangesFromContextDidSaveNotification:notification]; }]; } 

This works fine, and saving the private context and merging with mainContext does not trigger a contextWillSave notification. But when editing data from the user interface (on the main MOC), a notification is triggered and includes data that was previously saved using a private MOC.

Hope this is clear. Let me know if I should include anything else.

- UPDATE -

The problem seems to be related to the removal of objects from the private context. After removing from the private context and calling mergeChangesFromContextDidSaveNotification basically MOC, setMoc deletedObjects still shows the deleted object. This does not happen with inserts or updates in a private context. Is it documented anywhere? What could be the workaround?

+8
ios core-data nsmanagedobject nsmanagedobjectcontext
source share
2 answers

Modifying privateContextDidChange like this ...

 - (void) privateContextDidChange: (NSNotification *) notification{ if (notification.object == PrivateMOC) { [self.mainContext performBlockAndWait:^{ NSLog(@"merged into mainContext"); [self.mainContext mergeChangesFromContextDidSaveNotification:notification]; }]; } } 

... where is PrivateMOC a reference to the Content of a managed managed entity?

+2
source share

Core Data has been around for several years, and the concurrency model has evolved over this time.

Concurrency flow restriction and blocking models use notifications to exchange changes between contexts. When the context has been saved, a notification will be broadcast with information about the changes. This information can be used to aggregate changes from one context to another. This never scaled particularly well and was often a serious problem for applications. The โ€œlockโ€ and โ€œthread limitโ€ models have been outdated for several years.

When the "queue restriction" was introduced, the concept of "nested contexts" was introduced with it. The context can have a parent context, and when the child context is saved, these changes are automatically passed to the parent (and no further). This is the recommended way to link changes between contexts when using a queue constraint.

Using mergeChangesFromContextDidSaveNotification: with an NSPrivateQueueConcurrencyType context is not recommended.

Core Data performs a large number of internal accounting operations and change tracking on your behalf. Typically, information is aggregated and combined during a save operation โ€” this is part of the processPendingChanges . When a save operation is performed inside performBlockAndWait: it may or may not be complete, which means that the changes (and any notification of the change) are incomplete or not occur at all. performBlockAndWait: is reentrant, which is incompatible with the processPendingChanges process. Using performBlock: instead will result in more consistent behavior.

If you use nested contexts to convey changes, not notifications, your problem will be described by you during your question.

+1
source share

All Articles