码迷,mamicode.com
首页 > 编程语言 > 详细

Core Data 的线程安全问题

时间:2015-10-08 10:16:06      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

前言

很多小的App只需要一个ManagedContext在主线程就可以了,但是有时候对于CoreData的操作要耗时很久的,比如App开启的时候要载入大量数据,如果都放在主线程,毫无疑问会阻塞UI造成用户体验很差。通常的方式是,主线程一个ManagedContext处理UI相关 的,后台一个线程的ManagedContext负责耗时操作的,操作完成后通知主线程。使用CoreData的并行主要有两种方式:

Notificaiton child/parent context

何时会使用到后台或者是子线程-简单来说就是要耗费大量时间,如果在主线程上会影响用户体验的时候。

例如 : 导入大量数据 执行大量计算.

 

如下图所示,修改数据和删除数据用户同时执行,势必会阻塞主线程,这就涉及到Core Data的线程安全问题.

 

技术分享

 

一种比较好的iOS模式就是使用一个NSPersistentStoreCoordinator,以及两个独立的Contexts,一个context负责主线程与UI协作,一个context在后台负责耗时的处理。上下文改变后,默认会自动的发一个通知,监听通知即可再进行合并.

 

为什么说这样做的效率更高

这样做两个context共享一个持久化存储缓存,而且这么做互斥锁只需要在sqlite级别即可。设置当主线程只读的时候,都不需要锁。

 

具体实现代码如下所示 :

 

  1 #import "ViewController.h"
  2 #import <CoreData/CoreData.h>
  3 #import "User.h"
  4 #import "Movie.h"
  5 
  6 /**
  7  *  使用多线程操作CoreData
  8     1、为每一个多线程创建一个独立的NSManagedObjectContext 对象
  9     2、多个NSManagedObjectContext 对象可以共用一个NSPersistentStoreCoordinator 对象
 10     3、多线程修改MO数据之后,应该将修改的数据同步合并到主线程的 NSManagedObjectContext 对象中
 11  */
 12 
 13 @interface ViewController ()
 14 
 15 @end
 16 
 17 @implementation ViewController {
 18     NSManagedObjectContext *context;
 19     NSPersistentStoreCoordinator *store;
 20 }
 21 
 22 - (void)viewDidLoad
 23 {
 24     [super viewDidLoad];
 25    
 26     //监听所有NSManagedObjectContext 对象保存的事件
 27     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:nil];
 28    
 29     //打开数据库
 30     [self openDB];
 31 }
 32 
 33 
 34 - (void)contextDidSave:(NSNotification *)notification {
 35    
 36 //    NSManagedObjectContext *saveContext = notification.object;
 37    
 38     //将多线程中context中的MO数据合并到主线程的context中
 39     [context mergeChangesFromContextDidSaveNotification:notification];
 40     NSLog(@"合并上下文");
 41 }
 42 
 43 - (void)openDB {
 44    
 45     //1.加载数据模型文件
 46     NSURL *url = [[NSBundle mainBundle] URLForResource:@"CoreData" withExtension:@"momd"];
 47     //NSManagedObjectModel 用于加载数据模型文件
 48     NSManagedObjectModel *dataModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
 49    
 50     //2.打开数据库
 51     //NSPersistentStoreCoordinator 用于管理本地的数据库文件
 52     store = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:dataModel];
 53    
 54    
 55     //定义数据库文件的路径
 56     NSString *filePath = [NSHomeDirectory() stringByAppendingString:@"/Documents/coreData.sqlite"];
 57     NSURL *dbURL = [NSURL fileURLWithPath:filePath];
 58    
 59     NSError *error = nil;
 60     //打开数据库文件
 61     /**
 62      *  1.如果文件不存在,则新创建数据库文件
 63         2.如果文件存在,则直接打开
 64      */
 65     [store addPersistentStoreWithType:NSSQLiteStoreType
 66                         configuration:nil
 67                                   URL:dbURL
 68                               options:nil
 69                                 error:&error];
 70    
 71     if (error) {
 72         NSLog(@"打开数据库出错-%@",error);
 73         return;
 74     } else {
 75         NSLog(@"打开数据库成功");
 76     }
 77    
 78     //3.对数据做操作
 79     context = [[NSManagedObjectContext alloc] init];
 80     context.persistentStoreCoordinator = store;
 81 }
 82 
 83 - (IBAction)addData:(id)sender {
 84    
 85     //多线程
 86     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 87       
 88        NSManagedObjectContext *ctx = [[NSManagedObjectContext alloc] init];
 89        
 90         ctx.persistentStoreCoordinator = store;
 91        
 92         for (int i=0; i<1000; i++) {
 93            
 94             User *user = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:context];
 95            
 96             user.userID = [@(i) stringValue];
 97             user.age = @(i);
 98             user.name = [NSString stringWithFormat:@"li-%d",i];
 99            
100             UIImage *image = [UIImage imageNamed:@"093444.29353753_1280X720.jpg"];
101             user.image = UIImageJPEGRepresentation(image, 1);
102            
103         }
104        
105         if ([ctx save:nil]) {
106             NSLog(@"保存成功");
107         } else {
108             NSLog(@"保存失败");
109         }
110        
111     });
112   }
113 
114 
115 - (IBAction)asynFind:(id)sender {
116    
117     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
118     [queue addOperationWithBlock:^{
119             //多线程
120             NSManagedObjectContext *ctx = [[NSManagedObjectContext alloc] init];
121             ctx.persistentStoreCoordinator = store;
122            
123             NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"User"];
124            
125             NSArray *array = [context executeFetchRequest:request error:nil];
126            
127             for (User *user in array) {
128                
129                 user.name = @"张三";
130             }
131        
132         [ctx save:nil];
133     }];
134 }

 

Core Data 的线程安全问题

标签:

原文地址:http://www.cnblogs.com/pengsi/p/4860136.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!