Core Data线程安全及BUG解决

      1.Core Data线程安全问题:

      在一些简单项目中,一般只需要一个ManagedContext在主线程就可以了,但对于复杂项目来说,如果都放在主线程, 面对大数据量的读写必然阻塞主线程,用户体验极差。ManagedContext不是线程安全的,如果想要多线程访问CoreData的话,最好的方法是一个线程一个NSManagedObjectContext,每个NSManagedObjectContext对象实例都可以使用同一个NSPersistentStoreCoordinator实例,这个实例可以很安全的顺序访问永久存储,这是因为NSManagedObjectContext会在便用NSPersistentStoreCoordinator前上锁。
所以使用CoreData的并行主要有两种方式Notificaiton child/parent context。

        (1)Notificaiton 

        不同的线程使用不同的context进行操作,当一个线程的context发生变化后,利用notification来通知另一个线程Context,另一个线程调用mergeChangesFromContextDidSaveNotification来合并变化。

         Notification的种类

         NSManagedObjectContextObjectsDidChangeNotification 当Context中的变量改变时触发。

         NSManagedObjectContextDidSaveNotification 在一个context调用save完成以后触发。注意,这些managed object只能在当前线程使用,如果在另一个线程响应通知,要调用mergeChangesFromContextDidSaveNotification来合并变化。

         NSManagedObjectContextWillSaveNotification。将要save。

上个例子:

   NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

    [context performBlock:^{

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mocDidSaveNotification:) name:NSManagedObjectContextObjectsDidChangeNotification object:nil];

        YYBHouseDetail *house = (YYBHouseDetail *)[NSEntityDescription insertNewObjectForEntityForName:@"YiYibnb" inManagedObjectContext:context];

        house.title = @"123";

        NSError *error ;

        if (![context save:&error]) {

            NSLog(@"error is %@",error);

        }

        

    }];


-(void)mocDidSaveNotification:(NSNotification *)notification  {

    NSManagedObjectContext *context = [notification object];

    if (_myAppDelegate.managedObjectContext==saveContext) {

         return;

    }

    if (_myAppDelegate.managedObjectContext.persistentStoreCoordinator!=saveContext.persistentStoreCoordinator) {

        return;

    }

    dispatch_sync(dispatch_get_main_queue(), ^{

        [_myAppDelegate.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];

         });

}


              (2)child/parent context

       ChildContext和ParentContext是相互独立的。只有当ChildContext中调用Save了以后,才会把这段时间来Context的变化提交到ParentContext中,ChildContext并不会直接提交到NSPersistentStoreCoordinator中, parentContext就相当于它的NSPersistentStoreCoordinator。

通常主线程context使用NSMainQueueConcurrencyType,其他线程childContext使用NSPrivateQueueConcurrencyType. child和parent的特点是要用Block进行操作,performBlock,或者performBlockAndWait,保证线程安全。这两个函数的区别是performBlock不会阻塞运行的线程,相当于异步操作,performBlockAndWait会阻塞运行线程,相当于同步操作。

举例:

self.privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [self.privateContext setParentContext:self.mainContext];
    //执行耗时的操作

    //执行完毕
    [self.privateContext performBlock:^{
        NSError * error = nil;
        if ([self.privateContext hasChanges]) {
            [self.privateContext save:&error];
        }
    }];
   2.Core Data 系统BUG

当数据库中存在一对多且有序时,我们利用Model生成NSManagedObject文件中一对多有序关系会生成一个OrderSet,调用系统自动生成的插入删除方法时,程序有时候会崩,没错,这就是Core Data 的一个BUG,现在还苹果官方没有给出解决方案。我们在依依短租项目中的解决方案是重写系统生成的方法。在依依项目中,一个房子对应多张图片并且是有序的,根据Model生成的房屋类中存在@property (nullable, nonatomic, retain) NSOrderedSet<Image *> *images;这个属性,及下列方法:

- (void)insertObject:(Image *)value inImagesAtIndex:(NSUInteger)idx;

- (void)removeObjectFromImagesAtIndex:(NSUInteger)idx;

- (void)insertImages:(NSArray<Image *> *)value atIndexes:(NSIndexSet *)indexes;

- (void)removeImagesAtIndexes:(NSIndexSet *)indexes;

- (void)replaceObjectInImagesAtIndex:(NSUInteger)idx withObject:(Image *)value;

- (void)replaceImagesAtIndexes:(NSIndexSet *)indexes withImages:(NSArray<Image *> *)values;

- (void)addImagesObject:(Image *)value;

- (void)removeImagesObject:(Image *)value;

- (void)addImages:(NSOrderedSet<Image *> *)values;

- (void)removeImages:(NSOrderedSet<Image *> *)values;

我以重写insertObject为例,其余重写方法也类似,就不在贴代码了:

static  NSString  *image = @"images";


- (void)insertObject:(Image *)value inImagesAtIndex:(NSUInteger)idx {

    

    NSIndexSet* indexes = [NSIndexSet indexSetWithIndex:idx];

    

    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:image];

    

    NSMutableOrderedSet *tmpOrderedSet = [NSMutableOrderedSet orderedSetWithOrderedSet:[self mutableOrderedSetValueForKey:image]];

    

    [tmpOrderedSet insertObject:value atIndex:idx];

    

    [self setPrimitiveValue:tmpOrderedSet forKey:image];

    

    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexes forKey:image];

}



  


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值