核心数据并发:避免在两个不同的地方写入



我在登录私有上下文后正在做一些繁重的核心数据插入工作(比如 A)(以避免主线程阻塞)。不幸的是,在完成此操作之前,不幸的是,在代码中的某个地方也有一个插入工作(例如 B)(不重),但是必不可少的,并且还使用私有上下文来保存。

问题:在将记录保存在任何地方时,我检查它们是否已在数据库中(以确保唯一记录),但是在上述任务完成后,我检查coredata,我发现一些记录重复,这仅仅是由于在我调用"保存"之前在任务A,另一个进程B已经写入了重复记录。

我正在寻找解决方案,预见两种选择:

  1. 让第二个任务等待第一个任务(在另一个线程中调度并等待直到完成)
  2. 请推荐!!

编辑:事实证明,问题更多地与合并而不是并发有关,合并会产生重复记录,并发性很好,抛出的错误是:

NSCocoaErrorDomain Code=133020

更新:已使用覆盖合并策略修复合并问题

您在问题中自己说过,您的对象正在复制,因为您是从两个不同的位置保存的。

一种策略是使用相同的 NSManagedObjectContext 执行所有写入。很少需要创建多个后台上下文来执行写入(除非您的写入可能需要很长时间)。

话虽如此,很明显,您碰巧处于两个 Write 操作可以写入同一对象的位置。我将通过单个界面管理所有写入,然后此接口将保留用于编写的私有上下文。由于上下文是一个串行队列,因此您可以保证无法两次写入相同的对象(假设您的重复检查是坚如磐石的)。

所以你的界面可能看起来像这样:

@interface CoreDataManager : NSObject
+ (CoreDataManager*)sharedManager;
- (void)performWriteWithBlock:(void (^)(NSManagedObjectContext *writeContext))writeBlock;
@end
@implementation CoreDataManager
+ (CoreDataManager *)sharedManager {
    static dispatch_once_t once;
    dispatch_once(&once, ^ {
        self.writeContext = [[self class] createBackgroundPersistanceObjectContext];
    });
    return sharedManager;
}
- (void)performWriteWithBlock:(void (^)(NSManagedObjectContext *writeContext))writeBlock {
    if (writeBlock) {
        writeBlock(self.writeContext);
        [self.writeContext save:nil];
    }
}
+ (NSManagedObjectContext *)createBackgroundPersistanceObjectContext {
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [context setPersistentStoreCoordinator:coordinator];
    context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
    context.undoManager = nil;
    return context;
}
@end

尽管如此,您可以通过多种方式定义接口,但重要的是您有一个处理核心数据读取和写入的接口。

最新更新