CoreData 从入门到精通(四)并发操作
通常情况下,CoreData 的增删改查操作都在主线程上执行,那么对数据库的操作就会影响到 UI 操作,这在操作的数据量比较小的时候,执行的速度很快,我们也不会察觉到对 UI 的影响,但是当数据量特别大的时候,再把 CoreData 的操作放到主线程中就会影响到 UI 的流畅性。自然而然地我们就会想到使用后台线程来处理大量的数据操作。
使用后台 managedObjectContext
CoreData 里使用后台更新数据最常用的方案是一个 persistentStoreCoordinator
持久化存储协调器对应两个 managedObjectContext
管理上下文,NSManagedObjectContext
在创建时,可以传入 ConcurrencyType
来指定 context
的并发类型。指定 NSMainQueueConcurrencyType
就是我们平时创建的运行在主队列的 context
;指定成 NSPrivateQueueConcurrencyType
的话,context
就会运行在它所管理的一个私有队列中;另外还有 NSConfinementConcurrencyType
是适用于旧设备的并发类型,现在已经被废弃了,所以实际上只有两种并发类型。
下面是创建 backgroundContext
的代码:
NSManagedObjectContext *backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
backgroundContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
在最新的 iOS 10 中,CoreData 栈的创建被封装在了 NSPersistentContainer
类中,用它来创建 backgroundContext
更加简单:
NSManagedObjectContext *backgroundContext = ((AppDelegate *)[UIApplication sharedApplication].delegate).persistentContainer.newBackgroundContext;
另外,后台 context
的操作得放在 performBlock
或 performBlockAndWait
方法里执行,performBlock
会异步的执行,不会阻塞当前的线程,而 performBlockAndWait
则会阻塞当前的线程直到方法返回才会继续向下执行。下面是一段后台插入数据的示例代码:
[self.backgroundContext performBlock:^{
for (NSUInteger i = 0; i < 100000; i++) {
NSString *name = [NSString stringWithFormat:@"student-%d", arc4random_uniform(9999)];
int16_t age = arc4random_uniform(10) + 10;
int16_t stuId = arc4random_uniform(9999);
Student *student = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.backgroundContext];
student.studentName = name;
student.studentAge = age;
student.studentId = stuId;
}
NSError *error;
[self.backgroundContext save:&error];
[self.logger dealWithError:error
whenFail:@"failed to insert"
whenSuccess:@"insert success"];
}];
后台插入数据之后,还没有完,因为数据是通过后台的 context
写入到本地的持久化数据库的,所以这时候主队列的 context
是不知道本地数据变化的,所以还需要通知到主队列的 context
:“数据库的内容有变化啦,看看你有没有需要合并的”。这个过程可以通过监听一条通知来实现。这个通知就是 NSManagedObjectContextDidSaveNotification
,在每次调用 NSManagedObjectContext
的 save:
方法时都会自动发送,通知中的 userInfo
中包含了修改的数据,可以通过 NSInsertedObjectsKey
、NSUpdatedObjectsKey
、 NSDeletedObjectsKey
这三个 key 获取到。

收到通知之后,只需要调用 [self.mainContext mergeChangesFromContextDidSaveNotification:note]
就可以将修改的数据合并到主线程的 context
。
下面是示例代码:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveContextSave:) name:NSManagedObjectContextDidSaveNotification object:self.backgroundContext];
}
- (void)doSometingInsertingInBackground {
// backgroundContext ....
}
- (void)receiveContextSave:(NSNotification *)note {
[self.context mergeChangesFromContextDidSaveNotification:note];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
注意:通知的 userInfo
里保存的 managedObjects
不可以直接在另一个线程的 context
中直接使用!也就是 managedObject
不是跨线程的,如果想要在别的线程操作,必须通过 objectId
在另一个 context
里再重新获得这个 object
。
- (void)receiveContextSave:(NSNotification *)note {
[self.context mergeChangesFromContextDidSaveNotification:note];
NSSet<Student *> *managedObjects = note.userInfo[NSInsertedObjectsKey];
NSManagedObjectID *studentId = managedObjects.allObjects[0].objectID;
[self.context performBlock:^{
// 这是错的
// Student *wrongStudent = managedObjects.allObjects[0];
// 应该这么做
Student *student = [self.context objectWithID:studentId];
// modify student...
}];
}
CoreData 从入门到精通(四)并发操作的更多相关文章
- CoreData 从入门到精通(五)CoreData 和 TableView 结合
我们知道 CoreData 里存储的是具有相同结构的一系列数据的集合,TableView 正好是用列表来展示一系列具有相同结构的数据集合的.所以,要是 CoreData 和 TableView 能结合 ...
- CoreData 从入门到精通(三)关联表的创建
上篇博客中讲了 CoreData 里增删改查的使用,学到这里已经可以应对简单的数据存储需求了.但是当数据模型复杂起来时,例如你的模型类中除了要存储 CoreData 里支持的数据类型外,还有一些自定义 ...
- MyBatis从入门到精通(四):MyBatis XML方式的基本用法之增删改
最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 1. insert用法 1.1 简单的 ...
- Python基本语法[二],python入门到精通[四]
在上一篇博客Python基本语法,python入门到精通[二]已经为大家简单介绍了一下python的基本语法,上一篇博客的基本语法只是一个预览版的,目的是让大家对python的基本语法有个大概的了解. ...
- CoreData 从入门到精通 (一) 数据模型 + CoreData 栈的创建
CoreData 是 Cocoa 平台上用来管理模型层数据和数据持久化的一个框架,说简单点,就是一个数据库存储框架.CoreData 里相关的概念比较多,而且初始化也非常繁琐,所以对初学者的学习还是有 ...
- iOS开发-UI 从入门到精通(四)
一.UITextField 1.UITextField是什么? (1)UITextField(输入框):是控制文本输入和显示的控件.在App中UITextField出现频率也比较高: (2)iOS系统 ...
- CoreData 从入门到精通(六)模型版本和数据迁移
前面几篇文章中讲的所有内容,都是在同一个模型版本上进行操作的.但在真实开发中,基本上不会一直停留在一个版本上,因为需求是不断变化的,说不定什么时候就需要往模型里添加新的字段,添加新的模型,甚至是大规模 ...
- CoreData 从入门到精通(二) 数据的增删改查
在上篇博客中,讲了数据模型和 CoreData 栈的创建,那下一步就是对数据的操作了.和数据库一样,CoreData 里的操作也无非是增删改查.下面我们将逐步讲解在 CoreData 中进行增删改查的 ...
- Atom编辑器入门到精通(四) Atom使用进阶
在本节中将介绍Atom提供的更高级的使用技巧,通过这些技巧将会进一步提高你的代码编写效率 代码片段(Snippets) Snippets是一种在代码中快捷插入代码块的方式,下面是维基百科中对Snipp ...
随机推荐
- 2015.04.27,外语,读书笔记-《Word Power Made Easy》 12 “如何奉承朋友” SESSION 35
1.how to look 拉丁词根specto,to look的意思,是许多常见英文词语的来源,如spectacle(['spektәkl] n. 值得看的东西, 光景, 眼镜).spectator ...
- 【转】如何在Mac 终端升级ruby版本
原文网址:https://segmentfault.com/a/1190000003784636 rvm是什么?为什么要安装rvm呢,因为rvm可以让你拥有多个版本的Ruby,并且可以在多个版本之间自 ...
- 将字符串序列化Object格式
using Newtonsoft.Json; 首先引用 Newtonsoft.Json; 定义一个字符串 string str = "[{'ID':8.0,'PAGEID':201.0,' ...
- ros中文术语表及消息类型表
前言:整理一些ros常用表格,包括中文术语对照表. 一.中文术语表 二.消息类型表 -END-
- ubuntu下安装VMware
1 用apt-get命令更新系统 loginname@localhost:~$ sudo apt-get update 2 从官方网站下载Workstation11(Bundle Script) lo ...
- Android 自定义ScrollView的滑动监听事件
项目结构: 1.LazyScrollView类(自定义ScrollView) package android.zhh.com.myapplicationscrollview; /** * Create ...
- Unity 导入的模型检测不到碰撞
解决方案 添加Mesh Collider和rigidbody,并且Collider里边2个勾要勾上. 这是我碰到的问题.如果没解决你的问题,别打我,逃~
- MySQL_索引原理与慢查询优化
索引原理与慢查询优化 创建/删除索引的语法 #方法一:创建表时 CREATE TABLE 表名 ( 字段名1 数据类型 [完整性约束条件…], 字段名2 数据类型 [完整性约束条件…], [UNIQU ...
- CF #487 (Div. 2) D. A Shade of Moonlight 构造_数形结合
题意: 给 nnn个长度为 lll 且互不相交的开区间 (xi,xi+l)(x_{i}, x_{i}+l)(xi,xi+l) ,每个区间有一个移动速度 vvv,v∈1,−1v∈1,-1v∈1,−1 ...
- BZOJ 2141 排队 (三维偏序CDQ+树状数组)
题目大意:略 洛谷传送门 和 [CQOI2015]动态逆序对 这道题一样的思路 一开始的序列视为$n$次插入操作 把每次交换操作看成四次操作,删除$x$,删除$y$,加入$x$,加入$y$ 把每次操作 ...