coredata怎么处理多线程的问题呢,自从的iOS 5.0以后,苹果给的coredata添加了一些新的API,但是由于从前对于UI层面关注比较多,底层的东西关注过少,导致到现在才开始重新看CoreData这块的内容。
的iOS 5.0苹果为的coredata的并发处理添加了两个内容。
首先介绍第一个:
- (ID)initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)CT
NSManagedObjectContextConcurrencyType一共有三种:
- NSConfinementConcurrencyType
- NSPrivateQueueConcurrencyType
- NSMainQueueConcurrencyType
NSConfinementConcurrencyType
:每一条线程只能有唯一的一个ManagedObjectContext的模式。与此相对应,苹果的官方文档给出了两种解决并发问题的方案:
-
为每个线程创建一个单独的管理对象内容和共享一个持久性存储协调员。这是典型的推荐方法。
-
创建一个单独的管理对象上下文和持久性存储协调员为每个线程。这种方法提供了在更大的复杂性为代价更大的并发性(特别是如果你需要不同的沟通环境之间的更改),并增加了内存的使用。
NSPrivateQueueConcurrencyType
与 NSMainQueueConcurrencyType
:分别对应绑定一个后台线程与主线程。可以使用performBlock:开执行原来需要使用dispatch_async封装的代码.
NSConfinementConcurrencyType
不能执行performBlock
。
第二个内容:嵌套ManagedObjectContext
嵌套的环境让你建立一个托管对象的上下文,以便它访问数据从父上下文,而不是从持久性存储。如果您从具有父上下文管理对象上下文请求的对象,核心数据会先在父。如果父上下文在内存中的对象时,你会得到一个新的管理对象就是这样的。所以,如果有变化的父,你会得到更改版本的对象。如果该对象没有在这方面存在的,它会持续上涨,通过父上下文,直到它最后就会从持久性存储的数据。
也就是说,当子上下文中做保存操作时,因为子方面没有persistentStoreCoordinator 来合并异步操作到主线程,这也是这种结构的方便之处。
对于这种结构,我找到了来自弗洛里安·库格勒的几种并发策略:
策略一:
同样使用了嵌套ManagedObjectContext,但是使用了PrivateQueue作为主背景下,对于工人语境作操作将会经由MainQueue语境最终由MasterContext合并,这个方案的好处在于工Context都是临时工,不需要考虑他们的生命周期。另外的一个好处是,由于他们不能自动获取到来自父亲的更新,所以这个任务可以再未完成之前随时取消。
关于死锁
无论何时只要对PersistentStoreCoordinator做写的操作都会造成死锁,但是这个方案的一个好处在于,如果只是做读的操作,是从内存中的,所以不会造成死锁。但是死锁的问题还是要考虑进去的。
示例:
- (NSManagedObjectContext *)mainThreadContext {
如果(!_mainThreadContext){
_mainThreadContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSMainQueueConcurrencyType];
_mainThreadContext.parentContext = [自我backgroundContext];
}
返回_mainThreadContext;
}
- (NSManagedObjectContext *)backgroundContext {
如果(!_backgroundObjectContext){
_backgroundObjectContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_backgroundObjectContext setPersistentStoreCoordinator:_storeCoordinator];
}
返回_backgroundObjectContext;
}
- (NSManagedObjectContext *)temporaryContext {
NSManagedObjectContext * temporaryContext = [[NSManagedObjectContext页头] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = [自我mainThreadContext];
返回temporaryContext;
}
策略二:
传统的方式,两个线程都使用同一个持久化存取器,不使用嵌套的结构,而使用NSManagedObjectContextObjectsDidChangeNotification
合并来自其他线程的变化。这种方法处理起来要注意几点
每一条线程都应该是一个独立的ManagedObjectContext
监听NSManagedObjectContextObjectsDidChangeNotification
时,应该传递context,因为系统也可能会发送通知。
[[NSNotificationCenter defaultCenter]的addObserver:自我选择:@selector(managedObjectContextDidChanged :)名称:NSManagedObjectContextObjectsDidChangeNotification对象:ObjectContext的];
三种策略都可以处理的coredata并发的问题,有些人比较推崇的是第一个方案,但是同时弗洛里安Kugler经过测试发现当读取大量的数据时,策略二花费的总时间与在主线程花费的时间最少。详细原因可以阅读下面的文章。我觉得关于到底采取哪种方案还是通过自己的实践来。
参考