iPhone的iOS如何合并核心数据NSManagedObjectContext?
我试图在后台下载一些JSON对象,并做了相当多的multithreading。 一旦操作完成,我注意到这个断言失败了:
NSAssert([user.managedObjectContext isEqual:[AppUser managedObjectContext]],@"Different contexts");
如何将更改合并到[AppUser managedObjectContext]定义的主要上下文中?
我真的build议你阅读Marcus Zarra关于导入和显示大数据集核心数据的链接。
当你处理线程时,你创build的每个线程都需要有自己的上下文,写在jrturton提供的链接上。 然后,如果你想合并一个主要上下文(在主线程中创build的那个)和另一个上下文(你在上下文中使用的那个)之间的变化,你需要在主线程中监听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]; }
通知对象包含您在线程上下文中所做的更改。
一些笔记
线程很难实现。 我提供的链接使用NSOperation
及其上下文。 这是非常简单的设置,但自iOS 5以来,有一些function,使您的生活更轻松。
例如,要在不同的线程中创build上下文,您可以执行以下操作:
// 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 (eg 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堆栈。
希望能帮助到你。
你的特殊情况(在后台下载JSON)是很常见的。 我看到了一些没有多个上下文的实现。
在很多情况下,最简单而最为鲁莽的方法是让下载的对象通过协议或通知已完成的下载通知主线程。 然后你在主线程上进行保存。
在我的情况下,我正在使用RKObjectLoader的子类,并且有太多的线程和操作来跟踪正在发生的事情。 我发现可以很好地要求RKObjectStore通过要求加载的对象保存自己来为我合并更改。 (之前我问[AppUser managedObjectContext]
保存自己,这是错误的 )
正确的解决scheme包括请求加载的对象保存在自己的上下文中,如下所示:
- (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]; }