多个NSManagedObjectContext或单个上下文和-performBlock

11

我已经长期使用单个 NSManagedObjectContext 的 Core Data,所有的获取、保存和后台更新操作都是通过帮助类在单个上下文中完成的。我计划实现多个 NSManagedObjectContext 的方法(这是我大部分搜索中推荐的解决方案)。

我的问题是:使用 performBlock 是执行该上下文的代码的唯一方法吗?我们不能像下面这样做吗:

- (void) checkSyncServer {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        //do something here, check and fetch data
        // create NSManagedObject's 
        [_tempContext save:&error];  
        //masterContext will merge changes through notification observers
    });
}

即,执行除-performBlock方法之外的代码。我如何执行多个异步方法并执行保存操作?

然而,我发现一个由单例NSObject类管理的单一上下文更简单易用。

这个使用ContextConcurrencyType的多个上下文看起来更复杂(在执行流程方面)。是否有更好的解决方案?

1个回答

19

您可以通过以下两种方式之一访问上下文:

  • 在其线程/队列上。 适用于受限上下文和主队列上下文。 您可以自由地从它们自己的线程中访问它们。
  • 使用 -performBlock:,如果它是私有队列上下文或者您正在从不属于它所属的线程中访问该上下文。

您不能使用dispatch_async来访问上下文。 如果您想要异步执行操作,则需要使用-performBlock:

如果您以前正在使用单个上下文,并且使用dispatch_async来访问它,那么您就违反了线程限制规则。

更新

当您调用[[NSManagedObjectContext alloc] init]时,这与[[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]在功能上相同。

NSManagedObjectContext始终是线程限制的。

至于执行多个方法,您可以在同一个块中调用它们:

NSManagedObjectContext *moc = ...;
[moc performBlock:^{
  //Fetch something
  //Process data
  //Save
}];

或者,如果您希望它们彼此全部异步化,则可以将它们嵌套:

NSManagedObjectContext *moc = ...;
[moc performBlock:^{
  //Fetch Something
  [moc performBlock:^{
    //Process Data
  }];
  [moc performBlock:^{
    //Save
  }];
}];

因为-performBlock:是可重入安全的,所以您可以随意嵌套它们。

更新异步保存

要进行异步保存,您应该拥有两个(或更多)上下文:

  • 主队列上下文,用于UI交互
  • 私有队列上下文,负责保存

私有上下文拥有一个NSPersistentStoreCoordinator,而主队列上下文则将其作为父级。

所有工作都在主队列上下文中完成,您可以在主线程上安全地保存它。那次保存将是瞬时的。之后,您进行异步保存:

NSManagedObjectContext *privateMOC = ...;
NSManagedObjectContext *mainMOC = ...;

//Do something on the mainMOC

NSError *error = nil;
if (![mainMOC save:&error]) {
  NSLog(@"Main MOC save failed: %@\n%@", [error localizedDescription], [error userInfo]);
  abort();
}

[privateMOC performBlock:^{
  NSError *error = nil;
  if (![privateMOC save:&error]) {
    NSLog(@"Private moc failed to write to disk: %@\n%@", [error localizedDescription], [error userInfo]);
    abort();
  }
}];

如果您已经有一个应用程序,您只需要做以下几步:

  • 创建您的私有模型
  • 将其设置为主要模型的父级
  • 更改主要模型的初始化
  • 每次在主要模型上调用保存时添加私有块保存方法

您可以从那里进行重构,但那就是您真正需要更改的所有内容。


我没有使用任何特定的并发类型创建上下文,而是使用传统类型[[NSManagedObjectContext alloc] init]创建的。 - Ramesh Lingappa
另外,如何执行多个异步方法并进行保存?你能告诉我如何实现吗? - Ramesh Lingappa
我正在尝试实现异步父子上下文保存,参考链接:http://www.cocoanetics.com/2012/07/multi-context-coredata/。 - Ramesh Lingappa
感谢您的回复,多功能 performBlock,我知道我们可以使用它,但我觉得这不是一个更好的解决方案,所以在这里提出了一个问题,您的解释有助于决定实施它,知道使用它并不那么糟糕,而是为了自己的优点而设计的。 - Ramesh Lingappa
我能在不同的上下文中,调用performBlock内部的另一个performBlock吗? - Shyam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接