8

我了解这两个电话之间记录的差异。但是,有谁知道我注意到以下观察到的行为的原因:

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

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

在我看来,仅文档本身不足以解释这种行为。我当然可以把它归结为经验,然后说“我现在知道总是使用existingObjectWithID:将对象ID传递给我的孩子编辑上下文执行块时”但我感到不安,想确切地了解这里发生了什么(不是至少这样我可以理解使用一个对性能是否有任何影响,但也可以理解约束是什么,这样我就可以确保在我的代码中没有不必要地实施一些不好的做法,然后使用错误或低效的调用来修复它)。

4

3 回答 3

2

我在自己的代码中看到了这种行为(堆栈跟踪来自火星,花了很长时间才找到问题的原因),我的解决方案是相同的(从在子上下文中使用 objectWithID: 移动到使用现有的ObjectWithID:)。

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

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

在 iOS5 下,我会在工作线程中使用 objectWithID: 将新对象错误地放入导入上下文中。工作正常,没有问题。

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

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

于 2012-11-25T15:40:27.657 回答
1

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

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

在 Apple 文档中——也就是说,数据还没有在持久存储中,它位于父上下文中——我根本无法在父上下文中获取我实现的对象似乎仍然很奇怪。为什么持久存储必须知道它才能填充我的对象?

于 2013-11-07T20:23:21.813 回答
0

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

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

于 2013-03-14T08:56:02.393 回答