每个核心数据关系都必须有一个逆?

比方说,我有两个实体类: SocialAppSocialAppType

SocialApp我有一个属性: appURL和一个关系: type

SocialAppType我有三个属性: baseURLnamefavicon

SocialApp关系type的目标是SocialApp中的单个logging。

例如,对于多个Flickr账户,将会有一些SocialApplogging,每个logging都持有到一个人账户的链接。 对于“Flickr”types将有一个SocialAppTypelogging,即所有SocialApplogging都会指向的logging。

当我用这个模式构build一个应用程序时,我得到一个警告,即SocialAppTypeSocialApp之间没有反向关系。

  /Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse 

我需要一个逆,为什么?

在实践中,我没有任何数据丢失,至less我没有意识到。 一个快速的谷歌build议你应该使用它们:

相反的关系不仅使事情更加整洁,Core Data实际上使用它来维护数据的完整性。

– cocoa开发中心

您通常应该在两个方向上build模关系,并适当地指定相反的关系。 核心数据使用此信息来确保对象图的一致性(请参阅“处理关系和对象图完整性”)。 有关您可能不想在两个方向上build立关系的一些原因的讨论,以及一些如果您不这样做的问题,请参阅“单向关系”。

– 核心数据编程指南

苹果公司的文件有一个很好的例子,表明你可能有问题,没有反向关系的情况。 让我们把它映射到这种情况。

假设您将其build模如下: 在这里输入图像说明

请注意,您有一个从“ SocialApp到“ SocialAppType ”的称为“ type的一对一关系。 该关系是非可选的并且具有“拒绝”删除规则

现在考虑以下几点:

 SocialApp *socialApp; SocialAppType *appType; // assume entity instances correctly instantiated [socialApp setSocialAppType:appType]; [managedObjectContext deleteObject:appType]; BOOL saved = [managedObjectContext save:&error]; 

我们期望的是,这种上下文保存失败,因为我们已经设置删除规则为拒绝,而关系是非可选的。

但是这里保存成功。

原因是我们没有设定反比关系 。 因此,当appType被删除时,socialApp实例不会被标记为已更改。 所以在保存之前没有对socialApp进行validation(它假定没有需要validation,因为没有发生变化)。 但实际上发生了变化。 但是没有得到体现。

如果我们回想一下appType

 SocialAppType *appType = [socialApp socialAppType]; 

appType是零。

奇怪,不是吗? 我们得到零的非可选属性?

所以,如果你build立了相反的关系,你就没有麻烦了。 否则,您必须通过编写代码来进行强制validation,如下所示。

 SocialApp *socialApp; SocialAppType *appType; // assume entity instances correctly instantiated [socialApp setSocialAppType:appType]; [managedObjectContext deleteObject:appType]; [socialApp setValue:nil forKey:@"socialAppType"] BOOL saved = [managedObjectContext save:&error]; 

我将解释Dave Mark和Jeff LeMarche在“ 更多iPhone 3开发”中find的权威答案。

一般来说,Applebuild议您始终创build并指定反转,即使在应用程序中不使用反转关系。 出于这个原因,当你不能提供反向时,它会提醒你。

关系不需要有相反的关系,因为有一些情况,反向关系会影响性能。 例如,假设反比关系包含非常多的对象。 去除逆需要遍历表示反转,弱化性能的集合。

但是, 除非你有一个特定的原因,否则build模 。 它有助于核心数据确保数据完整性。 如果遇到性能问题,稍后删除相反关系相对容易。

更好的问题是,“有没有一个反面的原因”? 核心数据实际上是一个对象图pipe理框架,而不是一个持久性框架。 换句话说,它的工作就是pipe理对象图中对象之间的关系。 逆关系使得这容易。 出于这个原因,核心数据需要反向关系,并为该用例编写。 没有它们,你将不得不自己pipe理对象图的一致性。 尤其是,没有反向关系的多对多关系很可能会被Core Data破坏,除非您非常努力地工作。 对于反向关系来说,磁盘大小的成本与获得的收益相比确实微不足道。

至less有一种情况可以为核心数据关系提供一个好的情况,而不会出现逆转:当两个对象之间存在另一个核心数据关系时,将处理维护对象图。

例如,一本书包含很多页面,而一页是在一本书中。 这是一种双向多对一的关系。 删除一个页面只会使关系无效,而删除一个图书也会删除该页面。

但是,您也可能希望跟踪每本书正在阅读的当前页面。 这可以通过页面上的“currentPage” 属性完成,但是您需要其他逻辑来确保书中只有一个页面随时被标记为当前页面。 取而代之的是,从Book到单个页面的当前页面关系将确保总是只有一个当前页面被标记,并且此页面可以通过简单的book.currentPage轻松访问该书籍。

书籍和页面之间的核心数据关系的图形表示

在这种情况下,互惠关系会是什么? 有些东西很无意义。 “myBook”或其他类似的文件可能会被添加到另一个方向,但是它只包含已经包含在页面“book”关系中的信息,所以会产生自己的风险。 也许在将来,您使用这些关系之一的方式会发生变化,导致您的核心数据configuration发生变化。 如果page.myBook已经在一些应该在代码中使用page.book的地方使用,那么可能会有问题。 主动避免这种情况的另一种方法是,不要在用于访问页面的NSManagedObject子类中公开myBook。 然而,可以认为,不首先模拟倒数是比较简单的。

在下面的示例中,当前页面关系的删除规则应该设置为“无动作”或“级联”,因为与“消除”没有相互关系。 (Cascade意思是说,当你阅读的时候,你会把书中的每一页都撕掉,但是如果你特别冷,需要燃料的话,这可能是真的。)

当可以certificate对象图完整性没有风险时,如本例中,代码复杂性和可维护性得到改善,可以认为没有相反的关系可能是正确的决定。

虽然这些文档似乎并不需要反过来,但我只是解决了一个实际上导致“数据丢失”的情况,没有反过来。 我有一个在可报告对象上具有多对多关系的报表对象。 如果没有相反的关系,重新启动时对多对多关系的任何改变都会丢失。 核心数据debugging后,显然,即使我保存报表对象,对象图(关系)的更新从来没有被做出来。 我添加了一个反过来,即使我不使用它,瞧,它的作品。 所以它可能不会说这是必需的,但没有反向的关系肯定会有奇怪的副作用。