iOS CoreData详解(五)多线程
来源:互联网 发布:淘宝直播视频教程 编辑:程序博客网 时间:2024/05/19 22:58
原创blog,转载请注明出处
blog.csdn.net/hello_hwc
欢迎关注我的iOS SDK详解专栏,这里有很多基础的文章
http://blog.csdn.net/column/details/huangwenchen-ios-sdk.html
前言:很多小的App只需要一个ManagedContext在主线程就可以了,但是有时候对于CoreData的操作要耗时很久的,比如App开启的时候要载入大量数据,如果都放在主线程,毫无疑问会阻塞UI造成用户体验很差。通常的方式是,主线程一个ManagedContext处理UI相关的,后台一个线程的ManagedContext负责耗时操作的,操作完成后通知主线程。使用CoreData的并行主要有两种方式
- Notificaiton
- child/parent context
何时会使用到后台-简单来说就是要耗费大量时间,如果在主线程上会影响用户体验的时候。例如
- 导入大量数据
- 执行大量计算
CoreData与线程安全
有一点要时刻记住
CoreData不是线程安全的,对于ManagedObject以及ManagedObjectContext的访问都只能在对应的线程上进行,而不能夸线程。
有几条自己总结的规则
- 对于多个线程,每个线程使用自己独立的ManagedContext
- 对于线程间需要传递ManagedObject的,传递
ManagedObject ID
,通过objectWithID
或者existingObjectWithID
来获取 - 对于持久化存储协调器(NSPersistentStoreCoordinator)来说,可以多个线程共享一个NSPersistentStoreCoordinator
ManagedObjectContext的类型
- NSConfinementConcurrencyType - context使用thread confinement 模式
- NSPrivateQueueConcurrencyType - context在私有线程上的
- NSMainQueueConcurrencyType - context在主线程上
并行的解决方案之Notification
简单来说,就是不同的线程使用不同的context进行操作,当一个线程的context发生变化后,利用notification来通知另一个线程Context,另一个线程调用
mergeChangesFromContextDidSaveNotification
来合并变化。
Notification的种类
NSManagedObjectContextObjectsDidChangeNotification 当Context中的变量改变时候触发。
NSManagedObjectContextDidSaveNotification 在一个context调用save完成以后触发。注意,这些managed object只能在当前线程使用,如果在另一个线程响应通知,要调用
mergeChangesFromContextDidSaveNotification
来合并变化。- NSManagedObjectContextWillSaveNotification。将要save。
一种比较好的iOS模式就是使用一个NSPersistentStoreCoordinator,以及两个独立的Contexts,一个context负责主线程与UI协作,一个context在后台负责耗时的处理。
为什么说这样做的效率更高?
这样做两个context共享一个持久化存储缓存,而且这么做互斥锁只需要在sqlite级别即可。设置当主线程只读的时候,都不需要锁。
举例
主线程使用的Context,
- (NSManagedObjectContext *)managedObjectContext { // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) if (_managedObjectContext != nil) { return _managedObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (!coordinator) { return nil; } _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; [_managedObjectContext setPersistentStoreCoordinator:coordinator]; return _managedObjectContext;}
然后假设有一个BackgroundImport类是一个NSOperation的子类进行相关的后台操作,这里的子类执行是串行的。保存一个主线程属性
@interface BackgroundImport : NSOperation@property (strong,nonatomic)NSManagedObjectContext * mainContext;@end
保存一个私有的context
@interface BackgroundImport()@property (strong,nonatomic)NSManagedObjectContext * privateContext;@end
然后,在main函数里初始化,并且执行任务,这里一定要在main函数里初始化,因为main函数在创建的新线程上执行。并且注册通知合并变化
-(void)main{ self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [self.privateContext setPersistentStoreCoordinator:self.mainContext.persistentStoreCoordinator]; [[NSNotificationCenter defaultCenter] addObserverForName:NSManagedObjectContextDidSaveNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) { if (note.object == self.privateContext) { dispatch_async(dispatch_get_main_queue(), ^{ [self.mainContext performBlock:^{ [self.mainContext mergeChangesFromContextDidSaveNotification:note]; }]; }); } }]; //执行耗时的操作 //执行完毕 [self.privateContext performBlock:^{ NSError * error = nil; if ([self.privateContext hasChanges]) { [self.privateContext save:&error]; } }];}
使用的Demo,注意这里并不是后台线程,只是简单介绍下在实例中的应用
http://download.csdn.net/detail/hello_hwc/8759945
并行的解决方案之child/parent context
ChildContext和ParentContext是相互独立的。只有当ChildContext中调用Save了以后,才会把这段时间来Context的变化提交到ParentContext中,ChildContext并不会直接提交到
NSPersistentStoreCoordinator
中, parentContext就相当于它的NSPersistentStoreCoordinator。
child/parent context的结构图如下
这其中有几点要注意
- 通常主线程context使用NSMainQueueConcurrencyType,其他线程childContext使用NSPrivateQueueConcurrencyType.
- child和parent的特点是要用Block进行操作,
performBlock
,或者performBlockAndWait
,保证线程安全。这两个函数的区别是performBlock
不会阻塞运行的线程,相当于异步操作,performBlockAndWait
会阻塞运行线程,相当于同步操作。
举例
和上述类似,这次不需要监听变化,因为变化会自动提交到mainContext
self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [self.privateContext setParentContext:self.mainContext]; //执行耗时的操作 //执行完毕 [self.privateContext performBlock:^{ NSError * error = nil; if ([self.privateContext hasChanges]) { [self.privateContext save:&error]; } }];
Demo下载链接
http://download.csdn.net/detail/hello_hwc/8759969
关于大量数据操作性能差距方面,这篇文章有详细的阐述
性能评估博客
所以,如果对性能要求很高,还是两个独立的context公用一个持久化存储协调器较好
- iOS CoreData详解(五)多线程
- iOS CoreData详解(七)性能相关
- IOS开发 - CoreData详解
- IOS---CoreData详解
- [IOS 开发] CoreData多线程安全
- iOS 认识CoreData-多线程
- 转:ios coredata 教程 详解
- IOS-CoreData的使用详解
- iOS CoreData详解(四)Faulting and Uniquing
- iOS CoreData详解(六)深入理解数据模型
- iOS CoreData(2)
- Coredata多线程
- iOS SQLite、CoreData、FMDB数据库详解
- iOS中的CoreData的使用(详解)
- iOS CoreData数据库之创建详解
- iOS CoreData数据库之创建详解
- CoreData的使用以及coreData中的多线程问题(一)
- IOS CoreData 使用 (一)
- TreeView控件
- cookies的Base64()加密创建删除查询
- ViewPager的基本使用
- Sublime+scala
- 《PHP内核探索系列文章》系列技术文章整理收藏
- iOS CoreData详解(五)多线程
- Excel引用其他工作表数据的几种方法
- oozie
- IOS CoreText --- 支持图片及链接的点击
- 程序员经典语录
- 自定义View实现图片上传进度显示
- SQL语句大全(一)
- xbmc接受遥控键值并生成 XBMC_Event的过程
- Oracle备份dmp文件批处理