核心数据和线程/ Grand Central Dispatch

我是Grand Central Dispatch(GCD)和Core Data的初学者,我需要您的帮助才能将CGD与Core Data一起使用,以便在向Core Data添加40.000条logging时不会lockingUI。

我知道CD是不是线程安全的,所以我必须使用另一个上下文,然后保存数据和合并上下文,据我所知,从一些文章。

我还做不到的东西,把它们拼凑在一起。

所以,在我的代码中,我需要你的帮助。

我有:

/*some other code*/ for (NSDictionary *memberData in arrayWithResult) { //get the Activities for this member NSArray *arrayWithMemberActivities = [activitiesDict objectForKey:[memberData objectForKey:@"MemberID"]]; //create the Member, with the NSSet of Activities [Members createMemberWithDataFromServer:memberData andActivitiesArray:arrayWithMemberActivities andStaffArray:nil andContactsArray:nil inManagedObjectContext:self.managedObjectContext]; } 

我怎样才能转换这个工作的背景,然后,当完成保存,保存数据和更新用户界面,而不会阻止用户界面,同时保存40.000对象?

这是你尝试的一个很好的例子。 如果您有任何问题,请随时回来:

 self.mainThreadContext... // This is a reference to your main thread context NSPersistentStoreCoordinator *mainThreadContextStoreCoordinator = [self.mainThreadContext persistentStoreCoordinator]; dispatch_queue_t request_queue = dispatch_queue_create("com.yourapp.DescriptionOfMethod", NULL); dispatch_async(request_queue, ^{ // Create a new managed object context // Set its persistent store coordinator NSManagedObjectContext *newMoc = [[NSManagedObjectContext alloc] init]; [newMoc setPersistentStoreCoordinator:mainThreadContextStoreCoordinator]]; // Register for context save changes notification NSNotificationCenter *notify = [NSNotificationCenter defaultCenter]; [notify addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:newMoc]; // Do the work // Your method here // Call save on context (this will send a save notification and call the method below) BOOL success = [newMoc save:&error]; if (!success) // Deal with error [newMoc release]; }); dispatch_release(request_queue); 

并响应上下文保存通知:

 - (void)mergeChanges:(NSNotification*)notification { dispatch_async(dispatch_get_main_queue(), ^{ [self.mainThreadContext mergeChangesFromContextDidSaveNotification:notification waitUntilDone:YES]; }); } 

一旦完成后台线程上下文,不要忘记从通知中心删除观察者。

 [[NSNotificationCenter defaultCenter] removeObserver:self]; 

这是一个简单的术语,涵盖了GCD和UI。 你可以把你的代码replace成CoreData的工作。

关于CD和线程的安全性,关于GCD的一个很好的部分是你可以将应用程序(子系统)的区域分隔开来进行同步,并确保它们在同一个队列中执行。 您可以在名为com.yourcompany.appname.dataaccess的队列上执行所有CoreData工作。

在示例中,有一个button调用长时间运行的工作,一个状态标签,我添加了一个滑块来显示我可以在bg工作完成时移动滑块。

 // on click of button - (IBAction)doWork:(id)sender { [[self feedbackLabel] setText:@"Working ..."]; [[self doWorkButton] setEnabled:NO]; // async queue for bg work // main queue for updating ui on main thread dispatch_queue_t queue = dispatch_queue_create("com.sample", 0); dispatch_queue_t main = dispatch_get_main_queue(); // do the long running work in bg async queue // within that, call to update UI on main thread. dispatch_async(queue, ^{ [self performLongRunningWork]; dispatch_async(main, ^{ [self workDone]; }); }); // release queues created. dispatch_release(queue); } - (void)performLongRunningWork { // simulate 5 seconds of work // I added a slider to the form - I can slide it back and forth during the 5 sec. sleep(5); } - (void)workDone { [[self feedbackLabel] setText:@"Done ..."]; [[self doWorkButton] setEnabled:YES]; } 

本博客文章详细介绍了核心数据并发性和示例代码: http : //www.duckrowing.com/2010/03/11/using-core-data-on-multiple-threads/

添加另一个信息来源,你可以检查

ThreadedCoreData

苹果iOS开发者库的示例代码,最近更新(2013-06-09)

演示如何在multithreading环境下使用Core Data,遵循Core Data Programming Guide中提到的第一个build议模式。

基于SeismicXML示例,它下载并parsing美国地质调查局(USGS)提供的全球近期地震数据的RSS源。 这个例子的不同之处在于它坚持使用核心数据存储地震。 每次启动应用程序时,都会下载新的地震数据,并在NSOperation中进行parsing,检查重复数据并将新build地震存储为pipe理对象。

对于核心数据新手来说,将SeismicXML示例与本示例进行比较可能会有所帮助,并注意在应用程序中引入核心数据的必要成分。

所以select的答案是近2年前,现在有几个问题:

  1. 这不是ARC友好的 – 需要删除newMoc的发布调用 – ARC甚至不会编译
  2. 你应该在块内部做弱自我/自我跳舞,否则你可能会在创build观察者时创build一个保留循环。 请参阅Apple的文档: http : //developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html
  3. @RyanG在评论中问他为什么阻止。 我的猜测是因为最近编辑过的方法有waitUntilDone:YES – 除了会阻塞主线程。 你可能想waitUntilDone:不,但我不知道是否有UI更新从这些变化事件发射,所以这将需要testing。

– 编辑 –

进一步研究#3 – waitUntilDone:YES对于托pipe的上下文对象来说不是一个有效的方法签名,那么它是如何工作的呢?

更简单的方法来做,而不是将持久性存储协调器附加到一个新的上下文,这不是线程安全的,顺便说一句。

 NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrency]; [context setParentContext:<main thread context here>]; [context performBlock:^{ ... // Execute all code on current context ... }]; NSError *error = nil; [context save:&error]; if (!error) { [context.parentContext save:&error]; if (error) { NSLog(@"Could not save parent context: %@", error); } } else { NSLog(@"Could not save context: %@", error); } 

有关如何使用多上下文核心数据的很好的教程:

http://www.cocoanetics.com/2012/07/multi-context-coredata/