< p>I am developing a core data application where entities have a parent/child relationship. The application creates an NSManagedObjectContext (MOC) at startup. When the application runs for the first time, it uses an asynchronous block to import the contents of the plist into the second A MOC (the root node is obtained from the main MOC using URI and -managedObjectIDForURIRepresentation:), and the second context is saved just before the block is completed.
In my data controller, I subscribed to NSManagedObjectContextDidSaveNotification, And run the following code when sending the notification:
- (void)backgroundContextDidSave:(NSNotification *)notification {
if(![notification.object isEqual:self. managedObjectContext]){
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
withObject:notification
waitUntilDone:NO];
return;
}
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification]; ;
}
}
I have checked the integrity of this code , Of course, when the second MOC is saved, it is called from the thread that executed the block, then delayed, and run from the main thread. The notification object is included in the second MOC and imported All objects, including the two objects we will deal with next.
After finishing, I run the following code, which is located in the method of the NSManagedObject subclass to which the object belongs. It just means from the child parent Delete children from the middle:
TreeEntry *oldParent=self.parent; //keep a pointer to the old parent around so we can delete self from the children
< br />// These next four lines are a sanity check to make sure that both objects are on the same MOC we're saving
NSManagedObjectContext *selfContext=self.managedObjectContext;
NSManagedObjectContext *parentContext=self. parent.managedObjectContext;
NSManagedObjectContext *sharedContext=[[DataController sharedDataController] managedObjectContext];
assert([selfContext isEqual:parentContext] && [selfContext isEqual:sharedContext]);
/ / now we fault the two objects to make sure we can not possibly have them or any changes
// to them in the state of the main MOC, by this time the second MOC is long gone
[sharedContext refreshObject:self.parent mergeChanges:NO];
[sharedContext refreshObject:self mergeChanges:NO];
// up to this point, sharedContex.insertedObjects, sharedContext.updatedObects and sharedContext.deletedObjects
// have all contained no objects at all. None of the above was necessary as the MOC held no changes at all
[sharedContext saveChanges]; // we save it to, well, just to make sure I guess, I may be going crazy
// Now we carry out two changes to the objects, The problem occurs if only one change is carried out,
// I'm showing both to show that there relationship is being kept consistent and valid
self.parent=nil;
[oldParent removeChild: self];
// When the next line is run the save fails with a merge conflict
[sharedContext saveChanges];
The last save fails , Cocoa error 133020 appears, which is a merge failure. The two NSMergeConflicts in the error are related to the entries (self and self.parent) we are dealing with.
I just don’t understand what is going on. Object There is no state when they are modified, so they must be loaded from the store. Two simple changes are made, and then merge conflicts occur after saving them directly. How is it possible? Nothing else messed up the store, we just loaded its objects.
I know I can change the merge policy, but I don’t want to do it without knowing what is happening.
Any ideas? I am sure this is just my mental model, if what happens is wrong, but I have never been able to sort it out!
When I save the background context, the changes will go to disk, but obviously NSManagedStoreCoordinator (two contexts shared) will not update or invalidate its cache.
When When I refresh the objects in the main MOC, the data used to repopulate them comes from the cache, and the cache still has the old data. It will not be reloaded from the disk. The solution is to use [MOC setStalenessInterval: 0.0] to force a reload from the disk. < /p>
Thank you in advance for your help. I spent a lot of time fighting this today and I think I have some serious mistakes in the way the framework works.
p>
I am developing a core data application where entities have a parent/child relationship. The application creates an NSManagedObjectContext (MOC) when it starts. When the application runs for the first time, it uses an asynchronous block to plist the contents of Import the second MOC (the root node is obtained from the main MOC using URI and -managedObjectIDForURIRepresentation:), and save the second context just before the block is completed.
In my data controller, I subscribe I installed NSManagedObjectContextDidSaveNotification, and run the following code when sending notifications:
- (void)backgroundContextDidSave:(NSNotification *)notification {
if(![notification.object isEqual :self.managedObjectContext]){
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(backgroundContextDidSave:)
withObject:notification
waitUntilDone:NO];
return;
}
[self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification]; ;
}
}
I have This code is sanity checked. Of course, when the second MOC is saved, it is called from the thread executing the block, then delayed, and run from the main thread. The notification object contains all the objects imported in the second MOC, Including the two objects we will deal with next.
After finishing, I run the following code, which is located in the method of the NSManagedObject subclass to which the object belongs, it just means removing the child from the child parent :
TreeEntry *oldParent=self.parent; //keep a pointer to the old parent around so we can delete self from the children
/ / These next four lines are a sanity check to make sure that both objects are on the same MOC we're saving
NSManagedObjectContext *selfContext=self.managedObjectContext;
NSManagedObjectContext *parentContext=self.parent.managedObjectContext;
NSManagedObjectContext *sharedContext=[[DataController sharedDataController] managedObjectContext];
assert([selfContext isEqual:parentContext] && [selfContext isEqual:sharedContext]);
// now we fau lt the two objects to make sure we can not possibly have them or any changes
// to them in the state of the main MOC, by this time the second MOC is long gone
[sharedContext refreshObject:self .parent mergeChanges:NO];
[sharedContext refreshObject:self mergeChanges:NO];
// up to this point, sharedContex.insertedObjects, sharedContext.updatedObects and sharedContext.deletedObjects
// have all contained no objects at all. None of the above was necessary as the MOC held no changes at all
[sharedContext saveChanges]; // we save it to, well, just to make sure I guess, I may be going crazy
// Now we carry out two changes to the objects, problem occurs if only one change is carried out,
// I'm showing both to show that there relationship is being kept consistent and valid
self.parent=nil;
[oldParent removeChild:self];
// When the next line is run the save fails with a merge conflict
[sharedContext saveChanges ];
The last save failed with Cocoa error 133020, which is a merge failure. The two NSMergeConflicts in the error are related to the items we are processing (self and self.parent).
< p>I just don’t understand what’s going on. Objects have no state when they are modified, so they must be loaded from the store. Make two simple changes and then merge conflicts after saving them directly. How is it possible? Nothing else messed up the store, we just loaded its objects.
I know I can change the merge policy, but I don’t want to do it without knowing what is happening.
Any ideas? I am sure this is just my mental model, if what happens is wrong, but I have never been able to sort it out!
Well, this is a basic misunderstanding of how the framework works or more accurately the NSManagedStoreCoordinator cache.
When When I save the background context, the changes will go to disk, but obviously NSManagedStoreCoordinator (two contexts shared) will not update or invalidate its cache.
When I refresh the object in the main MOC, it is used to re The data that fills them comes from the cache, and the cache still has the old data. It will not be reloaded from the disk. The solution is to use [MOC setStalenessInterval:0.0] to force a reload from the disk.
p>