objectWithID:与existingObjectWithID之间无法解释的行为差异:

时间:2012-11-19 11:45:23

标签: ios core-data

我理解这两个调用之间记录的差异。但是,有人知道我注意到以下观察到的行为的原因:

如果我有一个parentContext和一个临时的childContext,我使用childContext来编辑,插入和删除对象,如果使用[childContext objectWithID:objectID];为了检索存在于父上下文中的已知现有托管对象,它有时会给我一个带有故障的对象,在被触发时失败并生成异常。我理解objectWithID:在设计中,无论是否存在给定objectID的实际managedObject,它总是会返回一个处于故障状态的对象。但是,如果对象实际存在于父上下文中,我希望当访问任何属性时,将始终从父上下文成功检索对象(例如,将触发错误)而没有任何问题。如果我使用[childContext existingObjectWithID:objectID];我发现它确实总能成功。

为了记录,我已经关闭了子上下文的缓存,并且在调用[childContext resetContext]之后发生了同样的行为 - 所以它不是悬挂在旧的缓存数据上的人工制品,与父上下文不一致。

在我看来,单独的文档不足以解释这种行为。我当然可以将它用于体验,并且只是说“我现在知道总是使用existingObjectWithID:当将对象ID传递给我的子编辑上下文执行块时”但我感到不安并且想要确切地了解这里发生了什么(不是至少所以我可以理解,如果使用一个相对于另一个有任何性能影响,但也了解约束是什么,所以我可以确保没有一些不好的做法,我在我的代码中不必要地实现,然后使用错误或低效的电话来修复它。)

3 个答案:

答案 0 :(得分:2)

我在自己的代码中看到了这种行为(堆栈跟踪来自Mars,永远追踪问题的原因),我的解决方案是相同的(从使用objectWithID:在子环境中转移)使用existingObjectWithID:)。

在我的情况下,我在父上下文中创建一个对象,立即获取它的永久对象ID,并使用UIManagedDocument的updateChangeCount:UIDocumentChangeDone请求保存,它将在将来的某个时间点安排保存。我认为这一点是讨论的关键。

然后我执行网络调用以获取与新创建的对象有关的XML数据,并将该数据解析并导入Core Data。这发生在后台线程上,我将对象ID传递给线程,该线程使用了线程限制的子导入上下文。

在iOS5下,我在工作线程中使用objectWithID:将新对象故障导入导入上下文。工作得很好,没有问题。

在iOS6下,这开始失败,有奇怪的堆栈跟踪,唯一的解决方案是转移到existingObjectWithID:。在测试中,这种变化似乎是一个可靠的解决方案。

和你一样,我试图找到一些明确的陈述,说明为什么会有效,但我没有成功。但是,我认为我的代码展示的模式和我看到的堆栈跟踪可能解释了正在发生的事情。我总是看到试图从持久性商店获取数据的崩溃。我相信在iOS5下,我通过UIManagedDocument请求的保存是在我的子线程有机会运行之前发生的,因此新对象在我调用objectWithID之前保持不变。从我的崩溃日志中可以看出,在iOS6下情况并非如此;线程在对象进入持久存储之前运行,因此它无法被提取到子上下文中。我的假设是existingObjectWithID:确保在尝试获取之前执行任何挂起的SQL I / O,因此当我的工作线程中发生提取时,持久存储是一致的。我一直无法找到支持这一点的明确命令,但广泛的测试似乎支持这就是正在发生的事情。

答案 1 :(得分:1)

与OP有相同的问题,虽然我认为例外是按照

设计的
  

如果对象未在上下文中注册,则可以将其作为故障提取或返回。此方法始终返回一个对象。假定objectID表示的持久性存储中的数据存在 - 如果不存在,则在访问任何属性时(即,触发错误时),返回的对象将引发异常。这种行为的好处是它允许您创建和使用故障,然后在以后或在单独的上下文中创建基础数据。

在Apple文档中的

- 也就是说,数据不在持久性存储中,它位于父上下文中 - 我仍然看起来很奇怪,我根本无法在父上下文中获取我实现的对象。为什么持久存储必须知道它,以便我的对象被填充?

答案 2 :(得分:0)

在使用existingObjectWithID获取“崩溃对象”之前使用objectWithID获取“现有对象”将导致两个对象相等。

只要访问“崩溃对象”的属性,应用程序的另一种方式就会崩溃。在这种情况下,对象不相等。 “崩溃对象”有一个临时的ObjectID。