4

我正在尝试在后台下载一些 JSON 对象,并且正在执行相当多的多线程。操作完成后,我注意到此断言失败:

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

如何将更改合并到 [AppUser managedObjectContext] 定义的主上下文中?

4

3 回答 3

11

我真的建议您阅读Marcus Zarra关于importing-and-displaying-large-data-sets-in-core-data的以下链接。

当您处理线程时,您创建的每个线程都需要有自己的上下文,如jrturton提供的链接中所写。然后如果你想合并一个主上下文(你在主线程中创建的那个)和另一个上下文(你在上下文中使用的那个)之间的变化,你需要NSManagedObjectContextDidSaveNotification在主线程中监听

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

并进行合并

- (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];
}

通知对象包含您在线程上下文中所做的更改。

一些笔记

线程很难实现。我提供的链接使用 anNSOperation及其上下文。这设置起来非常简单,但自从 iOS 5 以来,有一些功能可以让您的生活更轻松。

例如,要在不同的线程中创建上下文,您可以执行以下操作:

// 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];
}];

此外,您可以查看UIManagedDocument. 这个类很好地集成了 Core Data 并允许您避免使用 Core Data 堆栈。

希望能帮助到你。

于 2012-05-01T22:10:43.483 回答
1

您的特殊情况(在后台下载 JSON)很常见。我已经看到了许多不需要多个上下文的实现。

在许多情况下,最简单也是迄今为止最可靠的方法是让执行下载的对象通过协议或完成下载的通知通知主线程。然后,您在主线程上进行保存。

于 2012-05-01T22:19:45.750 回答
0

在我的情况下,我正在使用 RKObjectLoader 的子类,并且有太多的线程和操作来跟踪正在发生的事情。我发现可以通过要求加载的对象保存自己来很好地要求 RKObjectStore 为我合并更改。(在我要求[AppUser managedObjectContext]自救之前,这是错误的)

正确的解决方案涉及要求加载的对象将自己保存在自己的上下文中,如下所示:

- (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];

}
于 2012-05-02T18:08:23.480 回答