【问题标题】:Why does NSManagedObjectID change?为什么 NSManagedObjectID 会改变?
【发布时间】:2013-06-14 02:19:02
【问题描述】:

我不确定这个问题的格式是否适合这个网站。

基本上,有谁知道是什么说服了 Apple 做出设计决定,即每当您将数据保存到持久存储时 NSManagedObjectID 都会发生变化?

我可能错了,但这个决定对我来说听起来很可疑。 没有明显的优势(它是一个 UUID!它唯一的!),但它使传递 objectID 的 --- 它可以在保存对象时随时更改。

这对我来说是个大问题,因为我使用三个 MOC 系统(背景 MOC -> UI MOC -> Persistent MOC),对象被插入到背景 MOC 中并通过保存向上传播。保存是异步的,因为它必须在三个不同的 MOC 上传播并在创建后返回对象,但在将它们保存到持久存储之前非常痛苦,因为我不能依赖传递 objectID。

我做错了什么吗?有谁知道 UUID 在没有通知的情况下随时可变的优势是什么?

我最大的问题是为什么要提供临时 managedObjectID。这有什么意义吗?只是为了迷惑人们尝试使用它吗?

【问题讨论】:

  • @samson 我在谷歌搜索解决方案时看到了这个问题。我不确定它和我的有什么共同点——你能详细说明一下吗?在那个问题中,brianpartridge 询问为什么他不能将NSManagedObjectID 存储在单独的持久存储中,而我的问题是询问为什么它会在应用程序的单个生命周期中发生变异
  • @che 我会说没有欺骗 - 这与潜在的欺骗没有太多共同之处。
  • @Undo:感谢语法修复。
  • @DanShelly,我可以,但我觉得这种方法很混乱。如果您有 MOC 的层次结构,每个都在自己的队列上运行,并且您从最低的一个调用 obtainPermanent,请考虑这种情况。发生什么了?它是如何通过你的层次结构传播的?哪些 MOC 被阻止,哪些没有?它如何在不实际写入的情况下保留空间?只有苹果知道。

标签: ios core-data


【解决方案1】:

我有点困惑,为什么你一直说 NSManagedObjectID 是专门的 UUID。 URI 表示可能与 UUID 格式具有相似的外观,但我在文档中没有看到任何地方说“NSManagedObjectID 是 UUID”(正如我将在下面讨论的那样,它不仅如此)。为什么 Apple 以这种方式设计它超出了 StackOverflow 的范围,所以希望您的问题真的是“Core Data 的设计是什么,我该如何使用它?”

文档说(Managed Object IDs and URIs)是,如果你想做这种对象跟踪,你应该添加你自己的 UUID 作为属性:

您有时可以从创建自己的唯一 ID (UUID) 属性中受益,该属性可以为新插入的对象定义和设置。这允许您使用谓词有效地定位特定对象(尽管在保存操作之前只能在其原始上下文中找到新对象)。

NSManagedObjectID变化的原因可以从不可变的数据结构中看出。它包括一个persistentStore 属性。在您实际保存对象之前无法确定这一点(例如,您可能会调用assignObject:toPersistentStore:)。同样,不要从 URI 表示的角度考虑 NSManagedObjectID;这只是一种序列化格式。真实 ID 包括持久存储,如文档中所示:

与数据库中的主键一样,标识符包含准确描述持久存储中的对象所需的信息,尽管详细信息并未公开。

在插入对象之前,该标识符无法最终确定。

【讨论】:

  • 非常感谢!我一定误读了NSManagedObjectID 文档,对此感到抱歉 两个澄清:1)如果标识符本质上等同于主键,obtainPermanentIDsForObjects:error: 实际上对未保存的对象做了什么? 2) 临时 ID 的意义何在?可以用它们做任何有用的事情吗?
  • obtainPermanentIDsForObjects:error: 将其分配给商店(因此允许它拥有永久 ID)。此方法的参考文档进一步解释。您可以使用临时 id 来跟踪对象,直到它被保存。虽然它没有很多用途,但它比标识符 nil 更有用(因为你总是可以询问它是否是临时的,因此像 nil 一样对待它;你甚至可以添加一个辅助方法来做到这一点)。
【解决方案2】:

我绝不是Core Data 方面的专家,但我的理解是NSManagedObjectID大多数 情况下保证是唯一的。例外情况是:

  • 当您创建一个新对象但尚未提交时,它的 ID 将是临时的。您可以通过isTemporaryId 来检查这种情况。
  • 当后备存储发生变异时,即如果您使用 iCloud 并迁移到新版本的数据库。

由于您谈论的是单个生命周期,我假设我们正在研究第一个选项。如果是这种情况,您应该等到您的更改传播到持久存储之后再获取 id。我认为您可以从同一个对象中获取 id,即创建对象,保留指向它的指针,保存上下文,然后从保留的指针中获取该对象的 id。警告:我从来没有真正这样做过,这只是我根据阅读文档得出的结论。

此外,临时 id 应该一直存在,直到您保存上下文,所以您应该只需要担心一次 - 在第一次保存新对象的上下文之后。

顺便说一句,在我看来,CoreData 必须以这种方式实现。如果他们在实际将 id 插入持久存储之前试图保证 id 是唯一的,那么如果两个不同的上下文在提交之前抓取了相同的 id 会发生什么?保证唯一性/防止 id 出现某种竞争条件的唯一方法是在将记录插入数据库时​​找到唯一的 id...否则,CoreData 将不得不以某种方式插入一个虚拟值每条记录都有一个 child 上下文插入...

【讨论】:

  • 感谢解答,但是有两个问题:唯一保证唯一性的方法就是在向数据库中插入记录时找到唯一的id 不行!这是UUID。他们不需要“抓住”它。它与数据库中的主键无关。 您应该等到您的更改传播后才能获取 id 不。考虑后台线程上的 MOC,其父级是 UI MOC。后台线程的保存不能等待 UI MOC 保存,因为它会导致死锁。
  • 正如我所说,我不是专家。但是我在这里写的基本上是直接取自文档。此外,您似乎将 Rob Napier 的回答标记为正确,他基本上给出了与我给出的相同答案。 在插入对象之前无法最终确定该标识符。 我错过了什么吗?为什么投反对票?
  • 对不起,我现在无法更改它=(我基本上误读了文档。我发现您的陈述“必须以这种方式实现”非常具有误导性。在 WWDC2012 核心数据谈话, 他们特别建议在后台 MOC (其父对象是 UI MOC) 上创建对象. 现在在这种方法中, 在数据保存到持久存储之前暂停的唯一方法是在写入期间阻塞 UI 线程(因为保存通过 UI 线程)这可能会冻结 UI 几秒钟。
  • 我可以在你编辑答案后更改投票(否则系统不允许我)
  • 已编辑!现在误导少了吗?哪个部分有误导性?另外,我不相信您必须阻止 UI 是正确的。很确定我记得从 CoreData 的谈话中,他们专门讨论了如何避免在您描述的用例中阻塞 UI。不幸的是,我不记得他们说了什么;)也许您应该使用 NSFetchedResultsController?然后您不必阻止 UI,因为您会在成功添加新记录时收到通知……您为什么要暂停?我认为保存不需要通过 UI 线程。
猜你喜欢
  • 1970-01-01
  • 2010-12-18
  • 2011-01-15
  • 2020-11-14
  • 2014-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多