无论当前上下文状态如何,如何获取 NSManagedObject 的持久存储副本
Posted
技术标签:
【中文标题】无论当前上下文状态如何,如何获取 NSManagedObject 的持久存储副本【英文标题】:how to fetch persistent store copy of NSManagedObject regardless of current context state 【发布时间】:2014-01-21 02:24:26 【问题描述】:我正在开发一个使用 CoreData 和服务器 API 的应用程序。 我正在简化一点,但棘手的部分是当我更新关系(从关系中添加或删除对象)时,除了将其保存到 CD 之外,我还需要向服务器发送单独的 HTTP 请求以添加或删除这样的对象。
例如(我显然跳过了 JSON CD 解析方面),比如说我:
-
从服务器对象
O
中检索,关系R
(对多)最初持有另一个对象r0
。因此,在获取到服务器后,我的主要上下文包含 O.R = [r0]
。
然后我删除r0
并添加r1
。现在主上下文包含O.R = [r1]
。
目前,当我想将其提交回应用程序中的支持 SQL 并且服务器正在私有 GCD 队列上调度异步块时,我会做什么。块:
-
创建一个临时上下文,它只与主上下文共享存储协调器。
使用 temp 上下文检索
O
对象 O
的“已保存”(在 SQL 数据库中)版本。
主上下文中O
版本中的元素与刚刚通过临时上下文检索到的版本之间是否存在ObjectID
的差异。通过这种方式,我可以看出刚刚通过临时上下文检索到的版本有O.R = [r0]
,而主上下文中的当前版本有O.R = [r1]
。
从上面,我知道我必须发出一个调用来从服务器中删除r0
,然后另一个调用来添加r1
。
最后,我保存主要上下文,因为就CoreData 而言,O.R = [r1]
确实是新状态。 (请记住,仅在服务器更新时才需要根据每个对象确定删除的内容和添加的内容)。
现在的问题是,我想使用子上下文和-perfromBlock:
来代替。但是,如果我创建主上下文的子上下文而不是仅与主上下文共享存储协调器的临时上下文,我似乎无法找到一种方法来访问相关对象的“旧”版本SQL。即更改后,主上下文有O.R = [r1]
。如果我通过 id 通过子上下文获取相同的对象,我也会得到 O.R = [r1]
。另外,我尝试在子上下文上调用-refreshObject:
以查看这是否会强制子从 SQL 重新获取,但它仍然反映了主上下文的当前状态。我认为这与我不知道如何清除的缓存有关。
重点是,有没有办法强制子上下文从持久存储而不是缓存中获取?还是有其他方法可以获取相关对象的“旧”状态?
顺便说一句,-changedValues
和 -changedValuesForCurrentEvents
似乎都不能解决问题。
【问题讨论】:
【参考方案1】:没有办法强制孩子获取保存状态而不是当前状态。
您要么需要在修改对象之前获取对象,要么需要有一个单独的兄弟。另一种选择是拥有一个完全独立的堆栈,包括 PSC。
更新
兄弟是从同一个NSPersistentStoreCoordinator
或同一个父上下文扩展而来的两个上下文。
预先获取。创建子上下文,获取要在子上下文中修改的对象。然后修改父对象中的对象。子项不会被修改,因为上下文更改不会被下推。
这是一个 hack。 Core Data 不是为这样工作而设计的。 CD 首先是一个对象图,它非常努力地保持一切同步。我会重新考虑您在做什么并找到更清洁的解决方案。
更新
没有关于 iCloud 如何在内部工作的文档。但是,如果我要编写它,我会监听NSManagedObjectContextDidSave
通知,然后根据插入、更新和删除集构建事务日志。
【讨论】:
我不确定我是否遵循。在修改对象之前获取对象是什么意思?对于这个带有 O.R 和对象 r0 和 r1 的对象 O 的情况,在修改之前获取会是什么样子?我也不明白“兄弟姐妹”的概念。你愿意多解释一下吗?谢谢! 感谢您的更新。至于 CD 是一个图表,我很清楚这一点。不幸的是,我也需要让它与服务器保持同步。我可能会尝试“孩子的变化”方法。如果没有,至少我目前的方法确实有效。 这不是与服务器保持同步的最佳方式。如果您要保持“同步”,请考虑保留可以重放的事务日志。这就是 iCloud 的工作方式。这当然不同于作为一个简单合并策略就足够的服务器的缓存。 我喜欢事务日志的想法 :)。而且我正在考虑一种实现方式,但是您是否有任何链接或指针指向有关 iCloud 如何实现它的更多信息?以上是关于无论当前上下文状态如何,如何获取 NSManagedObject 的持久存储副本的主要内容,如果未能解决你的问题,请参考以下文章
无论当前的默认Locale如何,如何获取默认的ResourceBundle