如何在后台创建多个对象?

Kev*_*ers 10 multithreading core-data ios magicalrecord

我正在使用MagicalRecord 2.0.3,我无法弄清楚如何在后台保存数据.

根据文档,这样的东西应该工作:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) {
    // Do this hundreds of times
    [MyObject createInContext:localContext];
}];
Run Code Online (Sandbox Code Playgroud)

但是,没有任何内容保存到数据库中.我见过多个人发布类似这样的解决方案:

[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) {
    // Do this hundreds of times
    [MyObject createInContext:localContext];
} completion:^{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [[NSManagedObjectContext defaultContext] saveNestedContexts];
    }];
}];
Run Code Online (Sandbox Code Playgroud)

这确实将我的数据保存在数据库中,但是由于保存发生在主线程上,我的应用程序暂时没有响应(使用我的数据集,大约3秒,这太长了).

我也尝试过这个,但它在保存时也会阻塞:

self.queue = [[NSOperationQueue alloc] init];

[self.queue addOperationWithBlock:^{
    NSManagedObjectContext *localContext = [NSManagedObjectContext contextForCurrentThread];

    // Do this hundreds of times
    [MyObject createInContext:localContext];

    [localContext saveNestedContexts];
}];
Run Code Online (Sandbox Code Playgroud)

最后,与此代码相同的阻止效果:

dispatch_queue_t syncQueue = dispatch_queue_create("Sync queue", NULL);
dispatch_async(syncQueue, ^{
    NSManagedObjectContext *localContext = [NSManagedObjectContext contextForCurrentThread];

    // Do this hundreds of times
    [MyObject createInContext:localContext];

    [[NSManagedObjectContext contextForCurrentThread] saveNestedContexts];
});
Run Code Online (Sandbox Code Playgroud)

那么,解决这个问题的最佳方法是什么?我需要在后台创建数百个对象,应用程序需要保持响应.

Ona*_*ato 6

MagicalRecord在后台工作时使用子上下文.这适用于小的更改,但在导入大量数据时会产生过多的主线程阻塞.

这样做的方法是使用并行NSManagedObjectContext并自己与NSManagedObjectContextDidSaveNotification通知和mergeChangesFromContextDidSaveNotification方法合并.请参阅此处的性能测试:http://floriankugler.com/blog/2013/5/11/backstage-with-nested-managed-object-contexts

保存嵌套上下文时,必须将所有内容复制到父上下文.与此相反,未被提取的对象(在您要合并的上下文中)将不会被合并mergeChangesFromContextDidSaveNotification.这就是它更快的原因.

如果要在批量保存并使用NSFetchResultsController后立即显示这些结果,则可能会遇到问题.有关解决方案,请参阅以下问题: 带谓词的NSFetchedResultsController忽略从不同NSManagedObjectContext合并的更改

有关更多性能提示,请查看以下问题:在iOS 5上实现快速高效的核心数据导入

创建自己的上下文.

NSManagedObjectContext *importContext = [[NSManagedObjectContext alloc] 
                          initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[importContext setPersistentStoreCoordinator:yourPersistentStoreCoordinator];
[importContext setUndoManager:nil]; // For importing you don't need undo: Faster

// do your importing with the new importContext
// …

NSError* error = nil;
if(importContext.hasChanges) {
  if(![importContext save:&error]) {
      NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  } 
}
Run Code Online (Sandbox Code Playgroud)

确保您正在侦听对托管对象上下文的保存.

[[NSNotificationCenter defaultCenter] 
              addObserver:singleton 
                 selector:@selector(contextDidSave:)
                     name:NSManagedObjectContextDidSaveNotification object:nil];
Run Code Online (Sandbox Code Playgroud)

在contextDidSave中:您自己合并更改.

- (void) contextDidSave:(NSNotification*) notification
{
  if(![notification.object isEqual:self.mainContext]) {
    dispatch_async(dispatch_get_main_queue(), ^{
      [self.mainContext mergeChangesFromContextDidSaveNotification:notification];
    });
  }
}
Run Code Online (Sandbox Code Playgroud)