iOS:Core Data Merge 策略如何影响 NSManagedObjectContext 保存和刷新操作
Posted
技术标签:
【中文标题】iOS:Core Data Merge 策略如何影响 NSManagedObjectContext 保存和刷新操作【英文标题】:iOS: How do Core Data Merge policies affect NSManagedObjectContext Save and Refresh operations 【发布时间】:2017-11-19 15:50:39 【问题描述】:我一直在阅读有关 merge policies 的信息,它让我对何时合并更改产生了相互矛盾的想法。
我有两个上下文 - 一个在后台队列中,一个在主队列中。两者都有定义 NSOverwriteMergePolicy 的策略,我认为这是完全错误的。我已经遇到了同步问题。我经常看到在后台同步服务器数据时,我的 NSManagedObjects 经常过时,我最终保存它们,导致数据丢失。
是否有任何地方可以访问所有规则和优先顺序,以针对覆盖策略进行上下文保存、上下文刷新?
我已查看有关合并策略的所有文档,但我很困惑它们是否在 SAVE 或 REFRESH 时生效。
此外,在某种程度上,这非常令人困惑。例如,Apple Docs 声明此为 NSMergeByPropertyObjectTrumpMergePolicy
:
一种合并持久存储版本之间冲突的策略 对象和当前内存中的版本(按个人) 属性,外部更改胜过内存更改。 合并由单个属性发生。
对于在外部源和内存中都已更改的属性,内存中的 变化胜过外部变化。
当我选择在不同的上下文中修改/不修改它们时,如何确保我想要的属性得到修改/不受影响?
【问题讨论】:
【参考方案1】:TL:DR: 合并政策是邪恶的。您应该只以一种同步方式写入核心数据。
完整解释:如果一个对象同时从两个不同的上下文中更改,core-data 不知道该怎么做。您可以设置一个 mergePolicy 来设置哪个更改应该获胜,但这确实不是一个好的解决方案,因为这样您会丢失数据。许多专业人士长期以来一直在处理这个问题的方式是有一个操作队列来对写入进行排队,因此一次只有一个写入正在进行,并且在主线程上有另一个上下文仅用于读取.这样你就不会遇到任何合并冲突。 (有关此设置的详细说明,请参阅https://vimeo.com/89370886)。
使用NSPersistentContainer
进行此设置非常简单。在您的核心数据管理器中创建一个 NSOperationQueue
_persistentContainerQueue = [[NSOperationQueue alloc] init];
_persistentContainerQueue.maxConcurrentOperationCount = 1;
并使用此队列进行所有写入:
- (void)enqueueCoreDataBlock:(void (^)(NSManagedObjectContext* context))block
void (^blockCopy)(NSManagedObjectContext*) = [block copy];
[self.persistentContainerQueue addOperation:[NSBlockOperation blockOperationWithBlock:^
NSManagedObjectContext* context = self.persistentContainer.newBackgroundContext;
[context performBlockAndWait:^
blockCopy(context);
[context save:NULL]; //Don't just pass NULL here. look at the error and log it to your analytics service
];
]];
当您调用enqueueCoreDataBlock
时,该块被排入队列以确保没有合并冲突。但是,如果您写信给viewContext
,那将破坏此设置。同样,您应该将您创建的任何其他上下文(使用newBackgroundContext
或使用performBackgroundTask
)视为只读,因为它们也将在写入队列之外。
【讨论】:
以上是关于iOS:Core Data Merge 策略如何影响 NSManagedObjectContext 保存和刷新操作的主要内容,如果未能解决你的问题,请参考以下文章
iOS:Swift:Core Data:值不使用 Private ManagedObjectContext 存储
IOS/objective-c/core-data:如何从相关实体获取属性
如何从 PickerView 中的 Core Data 中获取数据? iOS