核心数据multithreading应用程序
我试图以multithreading的方式使用核心数据。 我只是想在后台下载新的数据的同时显示与以前下载的数据的应用程序。 这应该让用户在更新过程中访问应用程序。
我有一个NSURLConnection使用委托(并显示进度)asynchronous下载文件,然后我使用XMLParserparsing新的数据,并在独立的上下文中创build新的NSManagedObjects与自己的persistentStore和使用一个单独的线程。
问题是,在显示它的同一个上下文中创build新的对象可能会抛出BAD_INSTRUCTIONexception。 所以,我决定为新的数据使用一个单独的上下文,但我不能找出一种方法来完成后,将所有的对象移动到另一个上下文。
保罗又名SlowTree
核心数据文档的Apple Concurrency是开始的地方。 仔细阅读…我误会了很多次
基本规则是:
- 每个程序使用一个
NSPersistentStoreCoordinator
。 你不需要每个线程。 - 为每个线程创build一个
NSManagedObjectContext
。 - 切勿将线程上的
NSManagedObject
传递给其他线程。 - 相反,通过
-objectID
获取对象ID并将其传递给另一个线程。
更多规则:
- 确保在获取对象ID之前将对象保存到商店中。 直到保存,它们是临时的,你不能从另一个线程访问它们。
- 如果您对来自多个线程的pipe理对象进行更改,请注意合并策略。
-
NSManagedObjectContext
的-mergeChangesFromContextDidSaveNotification:
是有帮助的。
但请允许我重复一遍,请仔细阅读文档! 这真的很值得!
目前[2015年5月] ,核心数据文档的Apple Concurrency充其量是误导性的,因为它不包括iOS 5中的任何增强function,因此不再显示同时使用核心数据的最佳方式。 在iOS 5中有两个非常重要的更改 – 父上下文和新的并发/线程types。
我还没有find全面涵盖这些新function的书面文档,但WWDC 2012video“Session 214 – Core Data Best Practices”确实解释得非常好。
魔法logging使用这些新function,可能值得一看。
真正的基础仍然是一样的 – 你仍然可以只使用托pipe对象的pipe理对象上下文创build线程。
您现在可以使用[moc performBlock:]在正确的线程上运行代码。
没有必要再使用mergeChangesFromContextDidSaveNotification: 而是创build一个子上下文来进行更改,然后保存子上下文。 保存子上下文将自动将更改推送到父上下文中,并将更改保存到磁盘上,只需在其线程中执行父上下文的保存即可。
为了这个工作,你必须创build一个并发types的父上下文,例如:
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 ...> } }];
我希望这可以帮助所有在multithreading环境下使用核心数据解决问题的人们。
在苹果文档中查看“Top Songs 2”。 通过这个代码,我把matrix的“红色药丸”,发现了一个新的世界,没有双重自由的错误,没有错误。 :d
希望这可以帮助。
保罗
ps非常感谢Yuji,在你上面描述的文档中我发现了这个例子。