博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CoreData 从入门到精通(四)并发操作
阅读量:5205 次
发布时间:2019-06-14

本文共 3458 字,大约阅读时间需要 11 分钟。

通常情况下,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 的操作得放在 performBlockperformBlockAndWait 方法里执行,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,在每次调用 NSManagedObjectContextsave:方法时都会自动发送,通知中的 userInfo 中包含了修改的数据,可以通过 NSInsertedObjectsKeyNSUpdatedObjectsKeyNSDeletedObjectsKey 这三个 key 获取到。

NSManagedObjectContextDidSaveNotification-w600

收到通知之后,只需要调用 [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
*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... }]; }

转载于:https://www.cnblogs.com/Free-Thinker/p/7059726.html

你可能感兴趣的文章
pwn-ROP
查看>>
javaScript知识体系(上)- 变量、语句、函数、对象
查看>>
XAMPP添加二级域名
查看>>
nagios安装与配置
查看>>
利用DataSet更改数据,将更改保存到数据库中
查看>>
Partition(线段树的离线处理)
查看>>
poj3449Geometric Shapes
查看>>
利用WebApplicationInitializer配置SpringMVC取代web.xml
查看>>
MySQL DBA成长之路
查看>>
探秘启明星辰大数据安全分析平台
查看>>
Thread State
查看>>
Linux 动态链接库 - dll劫持
查看>>
Silverlight4 图片上传与位置标记
查看>>
AIC和BIC
查看>>
oracle生成主键
查看>>
秦旭光第一周任务
查看>>
java - day11 - OverRideTest
查看>>
Objective-C 内存管理之dealloc方法中变量释放处理
查看>>
iOS开发 viewWillAppear:(BOOL)animated真机调试的时候不执行了怎么办
查看>>
2019年高速免费
查看>>