多线程 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 - 如何使对象在不同的线程/上下文中保持最新?