Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 its 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). 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

like image 303
Cameron Avatar asked Mar 20 '12 17:03

Cameron


People also ask

Will you ever pass managed object from one context to another context?

You cannot pass NSManagedObjects between multiple contexts, but you can pass NSManagedObjectIDs and use them to query the appropriate context for the object represented by that ID.

Can we have more than one managed object context?

Most apps need just a single managed object context. The default configuration in most Core Data apps is a single managed object context associated with the main queue. Multiple managed object contexts make your apps harder to debug; it's not something you'd use in every app, in every situation.

What is context Core Data?

From your perspective, the context is the central object in the Core Data stack. It's the object you use to create and fetch managed objects, and to manage undo and redo operations. Within a given context, there is at most one managed object to represent any given record in a persistent store.

What is NSManagedObjectContext in Core Data?

An object space to manipulate and track changes to managed objects.


1 Answers

According to the WWDC 2011 presentation for "What's new in Core Data" it says you should save like this:

[child save:&error]; 
[parent performBlock:^{
    [parent save:&parentError];
}];

From my understanding this causes the parent to receive and merge in changes from the child context. One thing to note is that the parent and all children must be created with the same concurrency type.

-- Edit removed incorrect assumption that the parent pushes changes to the children, it does not.

like image 173
afrederick Avatar answered Oct 16 '22 22:10

afrederick