How to merge changes from one child managed object context to another via a parent MOC?
Hello (actual question at the bottom).


In iOS 5 there is the introduction of parent-child managed object contexts in CoreData.

I have a standard NSFetchedResultsController and UITableVeiwController working together to fetch a master list from the store. The fetched results controller's managed object context is a child with a parent context:

    // AppDelegate.m

    - (NSManagedObjectContext *)managedObjectContext
    {
        if (__managedObjectContext != nil)
        {
            return __managedObjectContext;
        }
    
        __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

        // primary managed object context has NSPrivateQueueConcurrencyType
        [__managedObjectContext setParentContext:[self primaryObjectContext]];
        return __managedObjectContext;
    }

The table view controller presents a modal view controller to add a new record, but uses a separate managed object context to do so (this context is another child of the parent context). This context gets saved in a delegate callback in the table view controller:


    - (void)addGame
    {
        // New child context
    
        [self setBuildManagedObectContext:[[NSManagedObjectContext alloc] init]];
        [[self buildManagedObectContext] setParentContext:[[[self team] managedObjectContext] parentContext]];
    
        Team *buildTeam = (Team *)[[self buildManagedObectContext] objectWithID:[[self team] objectID]];
        Game *buildGame = [NSEntityDescription insertNewObjectForEntityForName:@"Game" 
                                                    inManagedObjectContext:[self buildManagedObectContext]];
    
    
        [buildGame setTeam:buildTeam];
    
        BuildViewController *buildVC = [[BuildViewController alloc] initWithGame:buildGame delegate:self];
        UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:buildVC];
        [[self navigationController] presentViewController:navCon animated:YES completion:nil];
    }

    #pragma mark - Build view controller delegate

    - (void)buildViewController:(BuildViewController *)controller didFinishWithSave:(BOOL)save
    {
        if (save)
        {
            NSError *error = nil;
            if (![[self buildManagedObectContext] save:&error])
            {
                NSLog(@"Error saving new game");
                abort();
            }
        }
        [self setBuildManagedObectContext:nil];
        [[self navigationController] dismissViewControllerAnimated:YES completion:nil];
    }

Question:

It was my understanding that with parent-child contexts, the parent context would get the save notification from its child, and then notify all it's children. So in my example, the build context should trigger the parent context to tell the fetched results controller to merge the changes.

This isn't happening for me, the records are successfully created, but the fetched results controller isn't picking them up.  I know it used to be the case you had to implement you own merge from the save notification (as seen in [CoreDataBooks][1]). But I thought the child-parent contexts solved this issue. I tried saving the child and then the parent, but didn't seem to make a difference. Can someone explain this to me please? (Note: These are not contexts on separate/background threads)

Many Thanks

  [1]: https://developer.apple.com/library/ios/samplecode/CoreDataBooks/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008405
How to merge changes from one child managed object context to another via a parent MOC?
===

Hello (actual question at the bottom).


In iOS 5 there is the introduction of parent-child managed object contexts in CoreData.

I have a standard NSFetchedResultsController and UITableVeiwController working together to fetch a master list from the store. The fetched results controller's managed object context is a child with a parent context:

    // AppDelegate.m

    - (NSManagedObjectContext *)managedObjectContext
    {
        if (__managedObjectContext != nil)
        {
            return __managedObjectContext;
        }
    
        __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

        // primary managed object context has NSPrivateQueueConcurrencyType
        [__managedObjectContext setParentContext:[self primaryObjectContext]];
        return __managedObjectContext;
    }

The table view controller presents a modal view controller to add a new record, but uses a separate managed object context to do so (this context is another child of the parent context). This context gets saved in a delegate callback in the table view controller:


    - (void)addGame
    {
        // New child context
    
        [self setBuildManagedObectContext:[[NSManagedObjectContext alloc] init]];
        [[self buildManagedObectContext] setParentContext:[[[self team] managedObjectContext] parentContext]];
    
        Team *buildTeam = (Team *)[[self buildManagedObectContext] objectWithID:[[self team] objectID]];
        Game *buildGame = [NSEntityDescription insertNewObjectForEntityForName:@"Game" 
                                                    inManagedObjectContext:[self buildManagedObectContext]];
    
    
        [buildGame setTeam:buildTeam];
    
        BuildViewController *buildVC = [[BuildViewController alloc] initWithGame:buildGame delegate:self];
        UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:buildVC];
        [[self navigationController] presentViewController:navCon animated:YES completion:nil];
    }

    #pragma mark - Build view controller delegate

    - (void)buildViewController:(BuildViewController *)controller didFinishWithSave:(BOOL)save
    {
        if (save)
        {
            NSError *error = nil;
            if (![[self buildManagedObectContext] save:&error])
            {
                NSLog(@"Error saving new game");
                abort();
            }
        }
        [self setBuildManagedObectContext:nil];
        [[self navigationController] dismissViewControllerAnimated:YES completion:nil];
    }

Question:

It was my understanding that with parent-child contexts, the parent context would get the save notification from its child, and then notify all it's children. So in my example, the build context should trigger the parent context to tell the fetched results controller to merge the changes.

This isn't happening for me, the records are successfully created, but the fetched results controller isn't picking them up.  I know it used to be the case you had to implement you own merge from the save notification (as seen in [CoreDataBooks][1]). But I thought the child-parent contexts solved this issue. I tried saving the child and then the parent, but didn't seem to make a difference. Can someone explain this to me please? (Note: These are not contexts on separate/background threads)

Many Thanks

  [1]: https://developer.apple.com/library/ios/samplecode/CoreDataBooks/Introduction/Intro.html#//apple_ref/doc/uid/DTS40008405