2010-01-26 96 views
55

我试图以多线程方式使用核心数据。 我只是想在后台下载新数据的同时显示应用程序和以前下载的数据。 这应该让用户在更新过程中访问应用程序。核心数据多线程应用程序

我有一个使用委托(并显示进度)异步下载文件的NSURLConnection,然后我使用XMLParser解析新数据,并在独立的上下文中创建新的NSManagedObjects,使用它自己的persistentStore并使用单独的线程。

问题是,在显示它的同一上下文中创建新对象时可能会抛出BAD_INSTRUCTION异常。 因此,我决定为新数据使用单独的上下文,但我无法找到一种方法来完成后将所有对象移动到其他上下文。

保罗又名SlowTree

回答

138

The Apple Concurrency with Core Data documentation是开始的地方。仔细阅读......我误会了很多次!

基本规则是:

  1. 使用一个NSPersistentStoreCoordinator每个程序。每个线程你都不需要它们。
  2. 每个线程创建一个NSManagedObjectContext
  3. 切勿将线上的NSManagedObject传递给其他线程。
  4. 而是通过-objectID获取对象ID并将其传递给另一个线程。

更多规则:

  1. ,请务必保存对象进店获取对象ID之前。在保存之前,它们是暂时的,并且您无法从其他线程访问它们。
  2. 如果您对来自多个线程的管理对象进行更改,请注意合并策略。
  3. NSManagedObjectContext-mergeChangesFromContextDidSaveNotification:是有帮助的。

但让我再说一遍,请仔细阅读文档!这真的很值得!

+1

我发现CoreDataBooks融合背景下的一个很好的例子(mergeChangesFromContextDidSaveNotification)。 非常感谢。 祝您有愉快的一天。 保罗又名SlowTree – SlowTree 2010-01-26 10:22:45

+0

哦,谢天谢地。我读这个解决了我的问题。 正在后台线程中导入大量数据并获取大量不可预知的异常。 在后台线程中实例化上下文而不是传递它似乎修复了我的isses。 – tobyc 2010-05-25 03:41:03

+2

本文档尚未更新,以利用iOS 5中非常重要的改进 - 我在我的答案中链接的视频现在是更好的参考。 – JosephH 2012-08-05 08:24:35

2

我希望这可以帮助所有在多线程环境中使用核心数据解决问题的人们。

在苹果文档中查看“Top Songs 2”。通过这段代码,我接过了Matrix的“红色药丸”,并且发现了一个新的世界,没有双重自由错误,没有错误。 :D

希望这会有所帮助。

Paolo

p.s. 非常感谢Yuji,在你上面描述的文档中,我找到了这个例子。

73

目前[2015年5月] Apple Concurrency with Core Data documentation充其量是误导性的,因为它不包括iOS 5中的任何增强功能,因此不再显示同时使用核心数据的最佳方式。iOS 5中有两个非常重要的更改 - 父上下文和新并发/线程类型。

我还没有找到全面涵盖这些新功能的书面文档,但WWDC 2012 video "Session 214 - Core Data Best Practices"确实很好地解释了这一点。

Magical Record使用这些新功能,可能值得一看。

真正的基础仍然是一样的 - 你仍然可以只使用托管对象的管理对象上下文创建线程。

您现在可以使用[moc performBlock:]在右侧线程上运行代码。

没有必要使用mergeChangesFromContextDidSaveNotification:anymore;而是创建一个子上下文来进行更改,然后保存子上下文。保存子上下文将自动将更改推送到父上下文中,并将更改保存到磁盘,只需在其线程中执行父上下文的保存即可。

对于这个工作,你必须创建一个并发类型父上下文,如:

mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 

然后在后台线程:

context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; 
[context setParentContext:mainManagedObjectContext]; 

<... perform actions on context ...> 

NSError *error; 
if (![context save:&error]) 
{ 
    <... handle error ...> 
} 
[mainManagedObjectContext performBlock:^{ 
    NSError *e = nil; 
    if (![mainContext save:&e]) 
    { 
     <... handle error ...> 
    } 
}]; 
+0

虽然WWDC链接似乎是错误的.. – Philip007 2012-10-01 00:51:26

+7

Upvote for up-to日期信息。 SO应该实施机制来促进与新技术发展相关的答案,并淡化那些过时的被接受的答案。感谢您推荐Magic Record框架。它的文档看起来非常好。我可能会在稍后尝试。 – Philip007 2012-10-01 00:53:55

+0

与您的代码片段相反,UIManagedDocument默认在专用队列中创建其父上下文,并在主队列中创建子上下文。任何想法为什么苹果这样做?这是完全武断的吗? – Philip007 2012-10-01 00:56:45