标签:
前言:
很多小的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 }
标签:
原文地址:http://www.cnblogs.com/pengsi/p/4860136.html