简体   繁体   中英

iPhone iOS how to merge Core Data NSManagedObjectContext?

I'm trying to download some JSON objects in the background and am doing quite a bit of multi threading. Once the operation completes, I noticed that this assertion fails:

NSAssert([user.managedObjectContext isEqual:[AppUser managedObjectContext]],@"Different contexts");

How can I merge changes into the main context defined by [AppUser managedObjectContext] ?

I really suggest you to read the following link on importing-and-displaying-large-data-sets-in-core-data by Marcus Zarra .

When you deal with threads, each thread you create needs to have its own context as written in the link which jrturton provided. Then if you want to merge changes between a main context (the one you created in the main thread) and the other context (the one you use in the context), you need to listen for NSManagedObjectContextDidSaveNotification in the main thread

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextHasChanged:) name:NSManagedObjectContextDidSaveNotification object:nil];

and do the merge like

- (void)contextHasChanged:(NSNotification*)notification
{
  if ([notification object] == [self mainObjectContext]) return;

  if (![NSThread isMainThread]) {
    [self performSelectorOnMainThread:@selector(contextHasChanged:) withObject:notification waitUntilDone:YES];
    return;
  }

  [[self mainObjectContext] mergeChangesFromContextDidSaveNotification:notification];
}

The notification object contains the changes you made in the thread context.

Some notes

Threading is difficult to achieve. The link I provided uses an NSOperation with its context. This is quite simple to set up but since iOS 5 there are some functionalities that make your life easier.

For example to create a context in a different thread you can do like the following:

// create a context with a private queue so access happens on a separate thread.
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// insert this context into the current context hierarchy
context.parentContext = context;
// execute the block on the queue of the context
[context performBlock:^{

      // do your stuff (e.g. a long import operation)

      // save the context here
      // with parent/child contexts, saving a context pushes the changes out of the current context
      NSError* error = nil;
      [context save:&error];
}];

In addition you can see the doc for UIManagedDocument . This class integrates well for Core Data and allows you to avoid using the Core Data stack.

Hope it helps.

Your particular situation (downloading JSON in the background) is quite common. I have seen a number of implementations that make do without multiple contexts.

In many cases, the simplest and by far the robustest way is to have the objects that do the downloads notify the main thread via protocol or notification of a finished download. You then do the saving on the main thread.

In my situation, I'm using a subclass of RKObjectLoader and there's way too many threads and operations to keep track of what's going on. I found that the RKObjectStore can be asked nicely to merge changes for me by asking the loaded object to save itself. (before I was asking [AppUser managedObjectContext] to save itself, which was wrong )

The correct solution involved asking the loaded object to save itself in its own context as follows:

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {

    AppUser* user = nil;
    for (id object in objects)
    {
         user = object;
    }
    NSError* error = nil;


/**this call fires the:    
//    - (void)mergeChanges:(NSNotification *)notification
within the rkmanagedobjectstore class and merges changes made in this background operation over to the main contxt
 */
 [[user managedObjectContext] save:nil];

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM