多线程 CoreData 应用程序中主上下文和私有上下文的推荐合并策略

Posted

技术标签:

【中文标题】多线程 CoreData 应用程序中主上下文和私有上下文的推荐合并策略【英文标题】:Recommended merge policies on main context & private context in multi-threaded CoreData app 【发布时间】:2014-02-26 09:35:20 【问题描述】:

我已阅读并尝试了解这样做的推荐做法,但我想就以下情况听取您的专家意见;

我使用 CoreData 并将主上下文分配给持久存储协调器。

- (void) setupCoreDataStack

    self.managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:[NSBundle allBundles]];
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];

    NSURL *url = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:@"Model.sqlite"];

    NSDictionary *options = @NSPersistentStoreFileProtectionKey: NSFileProtectionComplete,
                              NSMigratePersistentStoresAutomaticallyOption:@YES;
    NSError *error = nil;
    NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error];
    if (!store)
    
        NSError *deleteError = nil;
        if ([[NSFileManager defaultManager] removeItemAtURL:url error:&deleteError])
        
            error = nil;
            store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:options error:&error];
        

        if (!store)
        
            // Also inform the user...
            NSLog(@"Failed to create persistent store. Error %@. Delete error %@",error,deleteError);
            abort();
        
    

    self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    self.mainManagedObjectContext.persistentStoreCoordinator = psc;

我所有的异步工作线程(与后端同步,执行各种 BLE/CoreBluetooth 活动等)创建自己的私有上下文(从它们的异步调度线程中),然后使用 performBlock 执行在根据指南/建议最终保存私有上下文和主要上下文之前工作;

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
                                         (unsigned long)NULL), ^(void)

    //Create private context and lnk to main context..
    NSManagedObjectContext* privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

    //Link private context to main context...
    privateContext.parentContext = self.mainManagedObjectContext;

    //Perform login-mechanism in block
    [privateContext performBlock:^

        //Do the work!
        ...
        ...

        //Merge changes to main context!
        NSError* error = nil;
        if (![privateContext save:&error])
            abort();

        //Save main context to persistent store coordinator
        [self.mainManagedObjectContext performBlockAndWait:^

            NSError *mainError;
            if (![self.mainManagedObjectContext save:&mainError])
                abort();
        ];
    ];
);

我现在的问题是,合并策略在此设置中如何工作?当我为 mainContext 分配一个 mergePolicy 时,这是否适用于如何将更改从 mainContext 合并到 PSC,或者将私有上下文合并到主上下文时?

我的理解是否正确,如果在此设置中使用 NSMergeByPropertyObjectTrumpMergePolicy,如果将其分配给私有上下文,将确保私有上下文更改合并到主上下文,并且在以下情况下将使用私有对象有冲突吗?或者我是否也必须设置主上下文的 mergePolicy 才能工作?

感谢您的意见, /马库斯

【问题讨论】:

【参考方案1】:

通常您希望在主NSManagedObjectContext 上设置合并策略。但是我的第一个问题是,您是否遇到合并冲突?如果您没有得到任何内容,那么您是否需要更改合并策略?

我倾向于保留默认策略(合并错误),直到我真正遇到合并问题。否则,当您没有意识到存在合并情况时,您可能会通过合并工作掩盖问题。

【讨论】:

我最初忽略了它们,但是当我遇到冲突时必须定义一些值。老实说,我不知道这种冲突是否仍然存在,尽管由于我一直在做一些代码抛光,所以这是一个很好的测试,真的。我更多地在概念基础上发布了这个问题,寻找指导方针,因为我 a)从不更改主线程中的模型/数据(仅从 UI 读取),并且 b)具有多个可能同时具有私有上下文的异步线程(请求数据从后端,由于 BLE 活动更新状态,同步应用离线时所做的更改)。 快速测试并猜一猜;无需合并策略(目前),因为我没有冲突,并且一切正常。也就是说,我仍然很好奇,想一劳永逸地理解事物;如果我看到冲突,那么显然我需要查看冲突的哪里(例如,从私有合并到主上下文,或从主合并到 PSC),并相应地设置合并策略。或者,您是否建议私有上下文不需要需要合并策略? 只会写的孩子不需要合并策略。只有他们推送到(父级)的上下文需要它。他们从来没有合并冲突,因为他们只从单一来源读取。主上下文可能会发生冲突,因为用户和/或其他孩子可以同时更改数据。那就是如果你首先遇到了问题。 明白 - 并且有道理。不过,我还有一个后续行动;昨天我说没有冲突的时候有点太快了,因为后来我因为 CoreData 合并冲突而崩溃了。但是,这些对象的内容完全相同,但版本不同(一个有 3 个,另一个有 4 个),但这个数字不是我设置的。我怀疑它是一个自动生成的版本,每次我从我的 CoreData 模型实体创建类时都会增加?如果是这样,管理实体变更修订的建议是什么?一种方法显然是设置NSMergeByPropertyObjectTrumpMergePolicy... 本人对上述评论的澄清;我的意思是,我知道我没有更改实体的结构(属性/关系),但是当我在不同的实体中进行更改时,我确实生成了新的类(只是为了安全起见)。理想情况下,我宁愿不使用 mergePolicy(因为没有数据更改,只有版本号),并在我更改实体结构时手动控制每个实体的版本......?

以上是关于多线程 CoreData 应用程序中主上下文和私有上下文的推荐合并策略的主要内容,如果未能解决你的问题,请参考以下文章

CoreData 和 NSManagedObject 上下文 - 私有与主

同时使用 CoreData、多线程和绑定

CoreData - 如何使对象在不同的​​线程/上下文中保持最新?

CoreData从后台线程读取数据仍然阻塞UI界面的原因及解决

CoreData 多线程删除

CoreData 和一对多关系的并发错误