Reputation: 91
I'm stuck on this problem with CoreData and Parent-Child MOCs: when adding objects to child MOC, saving them and saving the parent MOC all the objects gets their attributes reset to defaultValue.
I pasted here the logs from the two MOCs, specifically are the "stringAttribute" and "date" attributes that in these log are reset.
I searched for this problem everywhere but i didn't find anything, I also looked at lots of implementation of Parent-Child MOCs but I can't figure out what I'm doing wrong.
Thanks in advance!
Here's the code snippets:
I add some NSManagedObject to the main context and then save with saveContext:
method
// Another singleton method
- (void)anotherMethod
{
[...]
[self.managedObjectContext insertObject:managedObject];
NSError *error;
save = [self saveContext:&error];
[...]
}
// Database manager singleton method
- (BOOL)saveContext:(DKError *__autoreleasing *)error
{
__block BOOL save = NO;
__block NSError *internalError;
[self.managedObjectContext performBlockAndWait:^{
internalError = nil;
[self.managedObjectContext log]; // See log 1.1 below
save = [self.managedObjectContext save:&internalError];
if (!save) {
NSLog(@"Error saving data in main context");
} else {
[self.managedObjectContext.parentContext performBlock:^{
internalError = nil;
save = NO;
[self.managedObjectContext.parentContext log]; // See log 1.2 below
save = [self.managedObjectContext.parentContext save:&internalError];
if (!save) {
NSLog(@"Error saving data to disk!");
}
}];
}
}];
*error = [DKError errorWithNSError:internalError]; // Custom error class
return save;
}
Parent - Child contexts code
- (NSManagedObjectContext *)writerObjectContext
{
if (_writerObjectContext != nil)
return _writerObjectContext;
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_writerObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_writerObjectContext setPersistentStoreCoordinator:coordinator];
}
return _writerObjectContext;
}
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setParentContext:[self writerObjectContext]];
return _managedObjectContext;
}
Log 1.1
Inserted objects:
{(
<Entity: 0x9595120> (entity: Entity; id: 0x9582d40 <x-coredata:///Entity/t24D0F98B-CB94-41D3-BEDD-79913454A9152> ; data: {
[...]
dateAttribute = "2013-07-12 10:36:31 +0000";
stringAttribute = ricercaEntity;
[...]
})
)}
Log 1.2
Inserted objects:
{(
<Entity: 0xb53ce80> (entity: Entity; id: 0x9582d40 <x-coredata:///Entity/t24D0F98B-CB94-41D3-BEDD-79913454A9152> ; data: {
[...]
dateAttribute = "2013-01-05 11:00:00 +0000";
stringAttribute = nil;
[...]
})
)}
UPDATE
I've should have mention that the managedObject
added to the context is initialized with context nil. Then before calling saveContext:
I check for existence of object.managedObjectContext
and if it's nil then I'll set that as [self managedObjectContext]
, the one created with the method above. So either if the managedObject
is created with nil context, or created with:
+ (id)newObjectForInsertion
{
return [[self alloc] initWithEntity:[self entityDescription] insertIntoManagedObjectContext:[DKDatabaseManager defaultManager].managedObjectContext];
}
the associated managedObjectContext is on the same queue (NSMainQueueConcurrencyType).
Otherwise if the managedObject
is create with +newObjectForInsertion
all of the saveContext:
concurrency-chain return YES and all the changes are passed to parent context.
I don't know if it's a bug or the way CoreData should work.
Same problem on Apple Developer Forums:
https://devforums.apple.com/thread/174677?tstart=90
Upvotes: 3
Views: 498
Reputation: 8928
You should init context with concurrencyType:
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
Also, set merge policy
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
NSMergeByPropertyObjectTrumpMergePolicy
This policy merges conflicts between the persistent store’s version of the object and the current in-memory version, giving priority to in-memory changes. The merge occurs by individual property. For properties that have been changed in both the external source and in memory, the in-memory changes trump the external ones.
Btw, I found similar question: strange-behavior-when-using-child-parent-nsmanagedobjectcontext look at the accepted answer which uses notifications to merge.
Upvotes: 1