Multi-Context CoreData

          写在前面的话,首先声明,我这只是对国外一篇博客的总结。因为时间关系,我就不做翻译了,而且我并不觉得译文比原文来的要好,这里附上原文地址,我还是推荐大家看原文http://www.cocoanetics.com/2012/07/multi-context-coredata/

           原文讲解了coredata并发操作的两种解决方案,按时间划分为iOS5推出前,以及iOS5后 。

           我们先看看coredata正常设置(single-context)的情况,我们在NSManagedObjectContext(MOC),也就是我们俗称的上下文中对进行CURD操作,如果我们执行save操作,moc和NSPersistentStoreCoordinator(PSC)就会保存在disk中,接着我们就可以在VC中展示我们最新的数据。这在大多数情况下,都可以正常进行,但如果我们此时要update大数据的话,save操作将会占据超过1/60秒,那此时VC就会假死甚至导致程序崩溃,显然这不是我们想要的。那我们就需要考虑coredata的并发,这里大家可以先看看官方文档中concurrency with coredata一文。

           

            在iOS5推出之前,我们可以用GCD解决这个问题,当然现在也可以用这种方法

            原理就是我们通过监听不同子线程中MOCS的改变,最后把变化整合到主线程的MOC中即可,coredata提供了NSManagedObjectContextDidSaveNotification.这个通知

             

             我们在后台线程中处理大数据

dispatch_async(_backgroudQueue,^{
    // create context for backgroud
     NSManagedObjectContext *tmpContext = [[NSManaged ObjectContext alloc]init];
    tmpContxt.persistentStoreCoordinator = _persistentStoreCoordinator;
    // something that takes long 

     NSError *error;
     if(![tmpContext save:&error])
     {
        //handle error
     }
 
});
          搭建简单的Coredata Stack      
- (void)_setupCoreDateStack
{
    // setup managed object model
    NSURL *modelURL = [[NSBundle mainBundle]URLForResource:@"Database" withExtension:@"momd"];
    _managedObjectModel =[ [NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
     
      // setup persistent stroe 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 =[ [NSManagedObject alloc]init];
     [_managedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinator];
    //subscribe to change notifications
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_mocDidSaveNotification:) name:NSManagedObjectContextDidSaveNotification object:nil];

}
           主线程的MOC合并变化
- (void)_mocDidSaveNotification:(NSNotification *)notification
{
   NSManagedObjectContext *savedContext = [notification object];
 
   // ignore change notifications for the main MOC
   if (_managedObjectContext == savedContext)
   {
      return;
   }
 
   if (_managedObjectContext.persistentStoreCoordinator != savedContext.persistentStoreCoordinator)
   {
      // that's another database
      return;
   }
 
   dispatch_sync(dispatch_get_main_queue(), ^{
      [_managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
   });
}
           需要特别注意的是,managedObject是不能在MOCS中传递的,但我们可以通过ObjectID来实现间接传递
NSManagedObjectID *userID = user.objectID;
 
// make a temporary MOC
dispatch_async(_backgroundQueue, ^{
   // create context for background
   NSManagedObjectContext *tmpContext = [[NSManagedObjectContext alloc] init];
   tmpContext.persistentStoreCoordinator = _persistentStoreCoordinator;
 
   // user for background
   TwitterUser *localUser = [tmpContext objectWithID:userID];
 
   // background work
});
            在ios5推出之后,增加了initWithConcurrencyType构造方法,我们可以使用Parent/Child Contexts方法来实现coredata的并发

          

            其实和构造子线程创造MOC原理大同小异,只需要注意代码上的差别即可

            在这里我们用initWithConcurrencyType方法构建Parent MOC

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
            child MOCS保存,parent MOC保存
NSMangedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = mainMOC;
 
[temporaryContext performBlock:^{
   // do something that takes some time asynchronously using the temp context
 
   // push to parent
   NSError *error;
   if (![temporaryContext save:&error])
   {
      // handle error
   }
 
   // save parent to disk asynchronously
   [mainMOC performBlock:^{
      NSError *error;
      if (![mainMOC save:&error])
      {
         // handle error
      }
   }];
}];
          这里需要注意的是每一个MOC需要用performBlock:(async)或者performBlockAndWait:(sync)两个方法以确保在正确的线程中工作,child MOCS不会从parent MOC自动更新,而且这种方法最人性化的一点是你可以设置保存以及取消按钮,点击保存按钮,parent MOC才会从child MOCS获取更新,如果点击取消按钮,你还是可以该干啥干啥,parent MOC是获取不到更新的


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值