CoreData并发处理

来源:互联网 发布:淘宝联盟如何推广 编辑:程序博客网 时间:2024/06/05 03:27

iOS 5.0 苹果为CoreData的并发处理添加了两个内容。

首先介绍第一个:

- (id)initWithConcurrencyType:(NSManagedObjectContextConcurrencyType)ct

NSManagedObjectContextConcurrencyType 一共有三种:

  • NSConfinementConcurrencyType
  • NSPrivateQueueConcurrencyType
  • NSMainQueueConcurrencyType

NSConfinementConcurrencyType:每一条线程只能有唯一的一个ManagedObjectContext的模式。与此相对应,苹果的官方文档给出了两种解决并发问题的方案:

  1. Create a separate managed object context for each thread and share a single persistent store coordinator. This is the typically-recommended approach.

  2. Create a separate managed object context and persistent store coordinator for each thread. This approach provides for greater concurrency at the expense of greater complexity (particularly if you need to communicate changes between different contexts) and increased memory usage.

NSPrivateQueueConcurrencyType 与 NSMainQueueConcurrencyType:分别对应绑定一个后台线程与主线程。可以使用performBlock:开执行原来需要使用dispatch_async封装的代码.

NSConfinementConcurrencyType不能执行performBlock:.

第二个内容: Nested ManagedObjectContext

Nested contexts allow you to set up a managed object context so that it accesses data from a parent context instead of from a persistent store. If you request an object from a managed object context that has a parent context, Core Data will first look in the parent. If the parent context has that object in memory, you’ll get a new managed object just like that one. So if there are changes in the parent, you’ll get the changed version of the object. If the object doesn’t exist in that context, it will keep going up through parent contexts until it finally fetches the data from the persistent store.

也就是说,当子Context中做保存操作时,因为子context没有persistentStoreCoordinator ,这个变化会首先推送给他的父context,这个操作将一直传递,直到找到没有父Context的RootContext为止,当rootContext收到这个消息的时候,rootContext自动合并了这次操作,并且做了最终的保存。所以子context查找时,同样也会首先从父context那里查找而不是直接与persistentStoreCoordinator交流。当使用这种结构时,不需要特别去监听NSManagedObjectContextObjectsDidChangeNotification 来合并异步操作到主线程,这也是这种结构的方便之处。

对于这种结构,我找到了来自Florian Kugler的几种并发策略:

策略一 :

同样使用了Nested ManagedObjectContext,但是使用了PrivateQueue作为主Context。对于Worker Context作操作将会经由MainQueue Context 最终由MasterContext合并。这个方案的好处在于Worker Context都是临时工,不需要考虑他们的生命周期。另外的一个好处是,由于他们不能自动获取到来自父亲的更新,所以这个任务可以再未完成之前随时取消。

关于死锁

无论何时只要对PersistentStoreCoordinator做写的操作都会造成死锁,但是这个方案的一个好处在于,如果只是做读的操作,是从内存中的,所以不会造成死锁。但是死锁的问题还是要考虑进去的。

策略一

示例:

- (NSManagedObjectContext *)mainThreadContext{if (!_mainThreadContext) {    _mainThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];    _mainThreadContext.parentContext = [self backgroundContext];}    return _mainThreadContext;}- (NSManagedObjectContext *)backgroundContext{    if (!_backgroundObjectContext) {        _backgroundObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];        [_backgroundObjectContext setPersistentStoreCoordinator:_storeCoordinator];    }    return _backgroundObjectContext;}- (NSManagedObjectContext *)temporaryContext{    NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];    temporaryContext.parentContext = [self mainThreadContext];    return temporaryContext;}

策略二 :

传统的方式,两个线程都使用同一个持久化存取器,不使用嵌套的结构,而使用NSManagedObjectContextObjectsDidChangeNotification合并来自其他线程的变化。这种方法处理起来要注意几点

每一条线程都应该是一个独立的ManagedObjectContext 监听NSManagedObjectContextObjectsDidChangeNotification 时,应该传递context,因为系统也可能会发送通知。

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(managedObjectContextDidChanged:) name:NSManagedObjectContextObjectsDidChangeNotification object:objectContext];

策略二

三种策略都可以处理CoreData 并发的问题,有些人比较推崇的是第一个方案,但是同时Florian Kugler经过测试发现当读取大量的数据时,策略二花费的总时间与在主线程花费的时间最少。详细原因可以阅读下面的文章。我觉得关于到底采取哪种方案还是通过自己的实践来。


0 0
原创粉丝点击