coreData 深入理解4 --总结 (线程安全与同步--iOS5 前后对比)
Core Data是iOS中很重要的一个部分,可以理解为基于SQLite(当然也可以是其他的Storage,如In-memory,只是SQLite比较常见)的一个ORM实现,所以有关系数据库的特性,又不用写SQL。顺便吐一下槽,官方说法是使用Core Data能减少50%-70%的代码量,但相信用过的人应该都心里明白,Core Data使用起来还是比较麻烦的,这也是为什么有不少的第三方类库来代替/二次包装Core Data。
稍微复杂的应用就有可能出现同时处理多份数据的情况,这就需要用到多线程Core Data。在 iOS 5之前,官方推荐的是使用「Thread Confinement」,就是每个线程使用独立的MOC(managed object context),然后共享一个PSC(persistent store coordinator)。同时在线程之间传递数据时,要传递objectID,而不是object,因为前者是线程安全的,后者不是。
如果A线程里,对PSC执行了CUD(create, update, delete)操作,其他线程如何感知呢?这就需要通过监听事件来实现。比如在线程A中监听「NSManagedObjectContextDidSaveNotification」事件,如果线程B中执行了CUD操作,线程A就能感知到,并触发响应的action,虽然可以通过noti userinfo来获取managed objects,但因为它们是关联到另一个MOC,所以无法直接操作它们,解决方法就是调用「mergeChangesFromContextDidSaveNotification:」方法。
用一张图来形容的话,大体就是这样:

- (void)_setupCoreDataStack
{
// setup managed object model
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Database" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
// setup persistent store coordinator
NSURL *storeURL = [NSURL fileURLWithPath:[[NSString cachesPath] stringByAppendingPathComponent:@"Database.db"]];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// handle error
}
// create MOC
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
// subscribe to change notifications
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_mocDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];
}
再来看看Notification Handler,主要作用就是合并新的变化。
- (void)_mocDidSaveNotification:(NSNotification *)notification
{
NSManagedObjectContext *savedContext = [notification object];
// ignore change notifications for the main MOC
if (_managedObjectContext == savedContext) {
return;
}
dispatch_sync(dispatch_get_main_queue(), ^{
[_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
});
}
这种方式实现起来和维护起来都有点麻烦,所以iOS 5中就出现了更加方便和灵活的实现,也就是「Nested MOC」。
[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
可以看到在初始化时可以选择ConcurrencyType,可选的有3个:
NSConfinementConcurrencyType
这个是默认项,每个线程一个独立的Context,主要是为了兼容之前的设计。
NSPrivateQueueConcurrencyType
创建一个private queue(使用GCD),这样就不会阻塞主线程。
NSMainQueueConcurrencyType
创建一个main queue,使用主线程,会阻塞。
还有一个重要的变化是MOC可以指定parent。有了parent后,CUD操作会冒泡到parent。一个parent可以有多个child。parent还可以有parent。
因为UI相关的数据必须在主线程获取,同时又要避免数据库的I/O操作阻塞主线程,所以就有了下面这个模型:

我对这种实现方式的一个困惑是:child无法得知parent的变化,也就是说,如果NSFetchedResultsController绑定了Main MOC,当Background Write MOC save时,NSFetchedResultsController为何能知晓?求指点。
这种方式比「Thread Confinement」稍微简单了点,也更明了。不过个人还是推荐使用MagicalRecord,因为实现起来更加简单,等有空再写一篇。
写了一个使用了这个模型的demo,配合TableView和NSFetchedResultsController,有兴趣的可以看下:https://github.com/limboy/coredata-with-tableview
2013/06/17更新
之前的困惑已消除,NSFetchedResultsController跟PSC无关,只要绑定的MOC有了save动作,NSFetchedResultsController就会收到通知,无论这个save操作有没有写入到持久层。
参考
- http://www.cocoanetics.com/2012/07/multi-context-coredata/
- http://www.slideshare.net/Inferis/adventures-in-multithreaded-core-data
- from http://blog.leezhong.com/ios/2013/06/16/ios-multi-thread-core-data.html
coreData 深入理解4 --总结 (线程安全与同步--iOS5 前后对比)的更多相关文章
- 深入理解Java之线程池
原作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本文归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则 ...
- 深入理解JVM(7)——线程安全和锁优化
Java中的线程安全 按照线程安全的“安全程度”由强至弱来排序,可以将Java语中各种操作共享的数据分为以下5类:不可变. 绝对线程安全. 相对线程安全. 线程兼容和线程对立. 1.不可变 不变的对象 ...
- 深入理解Java之线程池(爱奇艺面试)
爱奇艺的面试官问 (1) 线程池是如何关闭的 (2) 如何确定线程池的数量 一.线程池销毁,停止线程池 ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown() ...
- [转]深入理解Java之线程池
原文链接 原文出处: 海 子 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这 ...
- java高并发系列 - 第5天:深入理解进程和线程
进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.程序是指令.数据及其组织形式的描述,进程是程序的实体. 进程具有的 ...
- ios专题 -线程互斥与同步
[原创]http://www.cnblogs.com/luoguoqiang1985 今天遇见了这问题,决定要需要讨论下. 线程同步的方法: @synchronized 官方文档解释:The @syn ...
- vc++高级班之多线程篇[6]---线程间的同步机制①
①.线程同步的必要性: int g_Num = 0; UINT __cdecl ThreadProc(LPVOID lpParameter) { for (int idx = 0; idx &l ...
- Java多线程——线程之间的同步
Java多线程——线程之间的同步 摘要:本文主要学习多线程之间是如何同步的,如何使用volatile关键字,如何使用synchronized修饰的同步代码块和同步方法解决线程安全问题. 部分内容来自以 ...
- 线程池+同步io和异步io(浅谈)
线程池+同步io和异步io(浅谈) 来自于知乎大佬的一个评论 我们的系统代码从同步方式+线程池改成异步化之后压测发现性能提高了一倍,不再有大量的空闲线程,但是CPU的消耗太大,几乎打满,后来改成协程化 ...
随机推荐
- GUI 快捷键的实现思路
思路: 前提快捷键操作不可重复,即一个快捷键对应一个控件的动作 一个窗体保持一份快捷键的map映射 在相应的消息中获取快捷键列表如键盘消息 在控件类对象中定义一个默认的响应行为,比如Button按 ...
- [ucgui] 对话框5——鼠标位置和移动窗口
>_<" 这节主要是获取鼠标的位置和把窗口设置为可以移动.其中设置窗口可以移动用FRAMEWIN_SetMoveable(hFrameWin, 1)就行了.而获得鼠标位置则是利用 ...
- Javascript日期与C# DateTime 转换
DateTime的日期到了客户端为:"/Date(1346818058450+0800)/"; 转吧: var renderTime = function (dateTime) { ...
- JAVA学习Swing章节JPanel和JScrollPane面板的简单学习
package com.swing; import java.awt.Container; import java.awt.GridLayout; import javax.swing.JButton ...
- JSTL自定义标签
这节我们总结一下JSTL自定义标签相关内容. 1. 自定义标签简介 自定义标签主要用于移除JSP页面中的Java代码.Jsp页面主要是用来显示给前台的,如果里面有过多的java代码的话,会显得很乱,但 ...
- wicket基本控件使用笔记
Label new Label(“message”,”message content”); MutLineLabel new MutlineLabel(“message”, ...
- GEF - 制作一个简单图形化编辑框架笔记1
在首先来看看GEF是什么,GEF的全称是Graphical Editing Framework,图形化框架,可以利用此框架做图形化编.他的基本原理是采用MVC开发模式. 以下是一些例子 GEF里面包含 ...
- JS_Ajax基础
一:Ajax ajax 的全称是Asynchronous(异步) JavaScript and XML 在不刷新页面的情况下从服务器获取,提交数据的一种数据交互方式; 二:Ajax使用步骤概括 //1 ...
- 删除配置文件解决OS X各种WiFi无法连接的顽固问题,解决MAC无法连接wif的情况 Preferences
删除配置文件解决OS X各种WiFi无法连接的顽固问题 删除配置文件解决OS X各种WiFi无法连接的顽固问题1 记住现在wifi的密码并将wifi关闭2 前往文件夹/Library/Preferen ...
- Android布局优化之过度绘制
如果一个布局十分复杂,那么就需要来排查是否出现了过度绘制,如果出现了,那么很可能会造成刷新率下降,造成卡顿的现象.那么什么是过度绘制呢?过度绘制就是在同一个区域中叠加了多个控件.这就像小时候我们画画, ...