ios Core Data 多线程应用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2138252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:49:40  来源:igfitidea点击:

Core Data multi thread application

iosiphonemultithreadingcore-data

提问by SlowTree

I'm trying to use core data in a multi thread way. I simply want to show the application with the previously downloaded data while downloading new data in background. This should let the user access the application during update process.

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

I have a NSURLConnection which download the file asyncronously using delegate (and showing the progress), then i use an XMLParser to parse the new data and create new NSManagedObjects in a separate context, with its own persistentStore and using a separate thread.

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

The problem is that creating new objects in the same context of the old one while showing it can throws BAD_INSTRUCTION exception. So, I decided to use a separate context for the new data, but I can't figure out a way to move all the objects to the other context once finished.

问题是在旧对象的相同上下文中创建新对象同时显示它可能会引发 BAD_INSTRUCTION 异常。所以,我决定为新数据使用一个单独的上下文,但我无法想出一种方法将所有对象在完成后移动到另一个上下文。

Paolo aka SlowTree

保罗又名慢树

回答by Yuji

The Apple Concurrency with Core Data documentationis the place to start. Read it really carefully... I was bitten many times by my misunderstandings!

Apple Concurrency with Core Data 文档是起点。仔细阅读……我被我的误解咬了很多次!

Basic rules are:

基本规则是:

  1. Use one NSPersistentStoreCoordinatorper program. You don't need them per thread.
  2. Create one NSManagedObjectContextper thread.
  3. Never pass an NSManagedObjecton a thread to the other thread.
  4. Instead, get the object IDs via -objectIDand pass it to the other thread.
  1. NSPersistentStoreCoordinator每个程序使用一个。每个线程不需要它们。
  2. NSManagedObjectContext每个线程创建一个。
  3. 永远不要将NSManagedObject一个线程上的an 传递给另一个线程。
  4. 相反,通过获取对象 ID-objectID并将其传递给另一个线程。

More rules:

更多规则:

  1. Make sure you save the object into the store before getting the object ID. Until saved, they're temporary, and you can't access them from another thread.
  2. And beware of the merge policies if you make changes to the managed objects from more than one thread.
  3. NSManagedObjectContext's -mergeChangesFromContextDidSaveNotification:is helpful.
  1. 确保在获取对象 ID 之前将对象保存到商店中。在保存之前,它们是临时的,您无法从另一个线程访问它们。
  2. 如果您从多个线程对托管对象进行更改,请注意合并策略。
  3. NSManagedObjectContext-mergeChangesFromContextDidSaveNotification:是有帮助的。

But let me repeat, please read the document carefully! It's really worth it!

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

回答by JosephH

Currently [May 2015] the Apple Concurrency with Core Data documentationis, at best, very misleading as it doesn't cover any of the enhancements in iOS 5 and hence no longer shows the best ways to use core data concurrently. There are two very important changes in iOS 5 - parent contexts and new concurrency/threading types.

目前 [2015 年 5 月] Apple Concurrency with Core Data 文档充其量是非常具有误导性的,因为它没有涵盖 iOS 5 中的任何增强功能,因此不再显示并发使用核心数据的最佳方法。iOS 5 中有两个非常重要的变化——父上下文和新的并发/线程类型。

I have not yet found any written documentation that comprehensively covers these new features, but the WWDC 2012 video "Session 214 - Core Data Best Practices"does explain it all very well.

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

Magical Recorduses these new features and may be worth a look.

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

The real basics are still the same - you can still only use managed objects the thread their managed object context was created on.

真正的基础仍然是相同的 - 您仍然可以只使用创建其托管对象上下文的线程的托管对象。

You can now use [moc performBlock:] to run code on the right thread.

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

There's no need to use mergeChangesFromContextDidSaveNotification: anymore; instead create a child context to make the changes, then save the child context. Saving the child context will automatically push the changes up into the parent context, and to save the changes to disk just perform a save on the parent context in it's thread.

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

For this to work you must create the parent context with a concurrent type, eg:

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

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

Then on the background thread:

然后在后台线程上:

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

回答by SlowTree

I hope this can help all the peoples that meet problems using core data in a multithread environment.

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

Take a look at "Top Songs 2" in apple documentation. With this code i took the "red pill" of Matrix, and discovered a new world, without double free error, and without faults. :D

看看苹果文档中的“Top Songs 2”。使用这段代码,我服用了 Matrix 的“红色药丸”,发现了一个新世界,没有双重错误,也没有错误。:D

Hope this helps.

希望这可以帮助。

Paolo

保罗

p.s. Many thanks to Yuji, in the documentation you described above I found that example.

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