核心数据多线程应用程序

时间:2010-01-26 08:40:48

标签: ios iphone multithreading core-data

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

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

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

Paolo aka SlowTree

3 个答案:

答案 0 :(得分:149)

The Apple Concurrency with Core Data documentation是值得一去的地方。仔细阅读它...我的误解多次被咬了!

基本规则是:

  1. 每个程序使用一个NSPersistentStoreCoordinator。每个线程不需要它们。
  2. 为每个帖子创建一个NSManagedObjectContext
  3. 永远不要将线程上的NSManagedObject传递给另一个线程。
  4. 而是通过-objectID获取对象ID并将其传递给另一个帖子。
  5. 更多规则:

    1. 确保在获取对象ID之前将对象保存到商店中。在保存之前,它们是临时的,您无法从另一个线程访问它们。
    2. 如果您从多个线程更改托管对象,请注意合并策略。
    3. NSManagedObjectContext的{​​{1}}很有帮助。
    4. 但请允许我再说一遍,请仔细阅读文件!这真的很值得!

答案 1 :(得分:76)

目前[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:而是创建一个子上下文来进行更改,然后保存子上下文。保存子上下文会自动将更改推送到父上下文,并将更改保存到磁盘,只需在其主线程中对父上下文执行保存。

为此,您必须使用并发类型创建父上下文,例如:

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 ...>
    }
}];

答案 2 :(得分:2)

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

查看Apple文档中的“Top Songs 2”。用这个代码我拿了Matrix的“红色药丸”,发现了一个没有双重自由错误,没有错误的新世界。 :d

希望这有帮助。

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