CoreData多线程

1: 主线程修改了数据库的某一条记录,但是子线程没有发生变化,反过来一样的问题。这种情况一般是发生在app有多个NSManagedObjectContext,两个线程分别对其进行了读写操作。 

2: 有时候程序会莫名其妙的crash掉,这个有很多原因: 
          a: 有时候是因为两个线程同时读写数据库中的同一条记录。 
          b: 有时候根本找不到是哪里的原因。 
          这两种情况一般是发生在app只有一个NSManagedObjectContext,两个线程都对其进行了读写操作。 

在实际的开发当中,我遇到了各种各样的问题,如果是多线程操作数据库的话,个人建议: 
1: 最好一个线程对应一个NSManagedObjectContext。如果只有一个NSManagedObjectContext,并且多个线程对其进行操作,回出现许多不清不楚的问题。 
2:在每一个线程对应一个NSManagedObjectContext的时候,尽量一个线程只读写与其对应的context。在其完成操作的时候通知另外的线程去修改其对应的context。在apple的api中有NSManagedObjectContextDidSaveNotification, 它可以帮助你通知修改其它的contexts。 
eg: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:childThreadManagedObjectContext]; 

3: 有两种方法,一种是每一个线程有一个NSManagedObjectContext与persistent store coordinator, 另一种是每一个线程有一个但共享一个persistent store coordinator,我采用的第二种方法。

我有两个线程,一个UI主线程,一个后台线程,后台线程用它的NSManagedObjectContext不断操作数据库,同时用Notifications的方式通知主线程的NSManagedObjectContext进行mergeChangesFromContextDidSaveNotification操作。这是官网文档的方法。

4: CoreData中的NSManagedObjectContext在多线程中不安全,如果想要多线程访问CoreData的话,最好的方法是一个线程一个NSManagedObjectContext,每个NSManagedObjectContext对象实例都可以使用同一个 NSPersistentStoreCoordinator实例,这个实例可以很安全的顺序访问永久存储,这是因为 NSManagedObjectContext会在使用NSPersistentStoreCoordinator前上锁。

 5: 如果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];
     });
}
 

posted on 2017-05-16 10:32  鬼手渔翁  阅读(401)  评论(0)    收藏  举报

导航