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

CoreData 多线程下NSManagedObjectContext的使用

时间:2015-05-18 20:49:33      阅读:633      评论:0      收藏:0      [点我收藏+]

标签:

在Google的时候,我发现了这样两篇老外的博客(,)。前者是介绍NSManagedObjectContext在多线程下的三种设计,后者是博主对这三种设计进行的性能测试。下面我将一一介绍:
1. persistentStoreCoordinator<-mainContext<-privateContext
    这种设计就是我之前在项目中使用的,也是阻塞UI线程最严重的一种设计。它总共有两个Context,一个是UI线程中使用的mainContext,一个是子线程中使用的privateContext,他们的关系是privateContext.parentContext = mainContext,而mainContext是与Disk连接的Context,所以这种设计下,每当子线程privateContext进行save操作以后,它会将数据库所有变动Push up到其父Context,也就是mainContext中去,注意:这时子线程的save操作并没有任何关于Disk IO的操作。而后mainContext在UI线程又要执行一次save操作才能真正将数据变动写进数据库中,这里的save操作就与Disk IO有关了,而且又是在主线程,所以说这种设计是最阻碍UI线程的。
2. persistentStoreCoordinator<-backgroundContext<-mainContext<-privateContext
    这种设计是第一种的改进设计,也是上述的老外博主推荐的一种设计方式。它总共有三个Context,一是连接persistentStoreCoordinator也是最底层的backgroundContext,二是UI线程的mainContext,三是子线程的privateContext,后两个Context在1中已经介绍过了,这里就不再具体介绍,他们的关系是privateContext.parentContext = mainContext, mainContext.parentContext = backgroundContext。下面说说它的具体工作流程。
    在应用中,如果我们有API操作,首先我们会起一个子线程进行API请求,在得到Response后要进行数据库操作,这是我们要创建一个privateContext进行数据的增删改查,然后call privateContext的save方法进行存储,这里的save操作只是将所有数据变动Push up到它的父Context中也就是mainContext中,然后mainContext继续call save方法,将数据变动Push up到它的父Context中也就是backgroundContext,最后调用backgroundContext的save方法真正将数据变动存储到Disk数据库中,在这个过程中,前两个save操作相对耗时较少,真正耗时的操作是最后backgroundContext的save操作,因为只有它有Disk IO的操作。
3. persistentStoreCoordinator<-mainContext
    persistentStoreCoordinator<-privateContext
    第三种设计是最直观的一种设计,无论是mainContext还是privateContext都是连接persistentStoreCoordinator的。这种设计的工作流程是:
    首先在ViewController中要添加一个名为NSManagedObjectContextDidSaveNotification的通知
,然后子线程中创建privateContext,进行数据增删改查操作,直接save到本地数据库,这时在ViewController中会回调之前注册的NSManagedObjectContextDidSaveNotification的回调方法,在该方法中调用mainContext的mergeChangesFromContextDidSaveNotification:notification方法,将所有的数据变动merge到mainContext中,这样就保持了两个Context中的数据同步。由于大部分的操作都是privateContext在子线程中操作的,所以这种设计是UI线程耗时最少的一种设计,但是它的代价是需要多写mergeChanges的方法。(注:前两种parent,child的Context,一旦childContext调用save方法,其parentContext不用任何merge操作,CoreData自动将数据merge到parentContext当中)
总结:
    第一种设计是失败的设计,完全可以不考虑,第二种设计比较复杂繁琐,但是它是最方便而且UI线程的阻塞时间也是相对较少的一种。第三种设计是最少阻塞UI的一种,但是这种设计操作比较繁琐,应用场合是数据量比较大的应用,一般会应用在企业应用中,所以如果你不是企业级的应用或者不是数据量很大的应用,我还是推荐第二种设计。我根据第二种设计写了一个Demo,下面附上一些关键代码供大家参考:
    注:在参考代码之前大家可能要对NSManagedObjectContext的concurrencyType有所了解,还有就是performBlock和performBlockAndWait:方法的区别。
//这是appDelegate中的backgroundContext -(NSManagedObjectContext *)rootObjectContext { if (nil != _rootObjectContext) { return _rootObjectContext; } NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator != nil) { _rootObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [_rootObjectContext setPersistentStoreCoordinator:coordinator]; } return _rootObjectContext; }
//这是mainContext - (NSManagedObjectContext *)managedObjectContext { if (nil != _managedObjectContext) { return _managedObjectContext; } _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; _managedObjectContext.parentContext = [self rootObjectContext]; return _managedObjectContext; // _managedObjectContext = [[NSManagedObjectContext alloc] init]; // _managedObjectContext.persistentStoreCoordinator = [self persistentStoreCoordinator]; // return _managedObjectContext; }
//AppDelegate中saveContext方法,每次privateContext调用save方法成功之后都要call这个方法 - (void)saveContextWithWait:(BOOL)needWait { NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; NSManagedObjectContext *rootObjectContext = [self rootObjectContext]; if (nil == managedObjectContext) { return; } if ([managedObjectContext hasChanges]) { NSLog(@"Main context need to save"); [managedObjectContext performBlockAndWait:^{ NSError *error = nil; if (![managedObjectContext save:&error]) { NSLog(@"Save main context failed and error is %@", error); } }]; } if (nil == rootObjectContext) { return; } RootContextSave rootContextSave = ^ { NSError *error = nil; if (![_rootObjectContext save:&error]) { NSLog(@"Save root context failed and error is %@", error); } }; if ([rootObjectContext hasChanges]) { NSLog(@"Root context need to save"); if (needWait) { [rootObjectContext performBlockAndWait:rootContextSave]; } else { [rootObjectContext performBlock:rootContextSave]; } } }
//这是伪API方法,仅供Demo使用 +(void)getEmployeesWithMainContext:(NSManagedObjectContext *)mainContext completionBlock:(CompletionBlock)block { NSManagedObjectContext *workContext = [NSManagedObjectContext generatePrivateContextWithParent:mainContext]; [workContext performBlock:^{ Employee *employee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:workContext]; [employee setRandomData]; NSError *error = nil; if([workContext save:&error]) { block(YES, nil, nil); } else { NSLog(@"Save employee failed and error is %@", error); block(NO, nil, @"Get emploree failed"); } }]; }
//这是NSManagedObjectContext的Category @implementation NSManagedObjectContext (GenerateContext) +(NSManagedObjectContext *)generatePrivateContextWithParent:(NSManagedObjectContext *)parentContext { NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; privateContext.parentContext = parentContext; return privateContext; } +(NSManagedObjectContext *)generateStraightPrivateContextWithParent:(NSManagedObjectContext *)mainContext { NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] init]; privateContext.persistentStoreCoordinator = mainContext.persistentStoreCoordinator; return privateContext; } @end
//这是ViewController里API操作和UI刷新的相关代码,从refreshData方法 -(void)refreshData { [EmployeeTool getEmployeesWithMainContext:[self mainContext] completionBlock:^(BOOL operationSuccess, id responseObject, NSString *errorMessage) { if ([NSThread isMainThread]) { NSLog(@"Handle result is main thread"); [self handleResult:operationSuccess]; } else { NSLog(@"Handle result is other thread"); [self performSelectorOnMainThread:@selector(handleResult:) withObject:[NSNumber numberWithBool:operationSuccess] waitUntilDone:YES]; } }]; } -(void)handleResult:(BOOL)operationSuccess { if (operationSuccess) { NSLog(@"Operation success"); [self saveContext]; } [self.refreshControl endRefreshing]; } -(void)saveContext { WMAppDelegate *appDelegate = (WMAppDelegate*)[UIApplication sharedApplication].delegate; [appDelegate saveContextWithWait:NO]; }

CoreData 多线程下NSManagedObjectContext的使用

标签:

原文地址:http://blog.csdn.net/zhangping871/article/details/45826799

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