掌握CoreData(第7部分核心数据关系删除规则)
正如我们在第5部分和第6部分中讨论的,当我们创建实体之间的关系时。 每个实体NSManagedObject与一个实体描述(NSEntityDescription的一个实例)相关联,该实体描述提供有关对象的元数据。 对象元数据包括对象代表的实体的名称以及其属性和关系的名称。 创建关系时,应考虑许多事项,删除规则就是其中之一。
删除规则
删除规则是使用Core Data的一大便利。 每个关系都有删除规则。 它定义了删除拥有关系的记录时发生的情况。
要么
关系的删除规则指定了尝试删除源对象时应该发生的情况。
在这一部分中,我们将使用之前的实体来了解删除规则。 下载Todo应用程序。 首先我们将做一些理论上的部分,然后我们将使用实际编码对其进行测试
核心数据支持四种删除规则:“层叠”,“拒绝”,“无效”和“不执行操作”。
级联
删除源时,请删除关系目标处的对象。 如果我们删除用户,则与该用户关联的所有任务也将被删除
要添加实体之间的关系,请参阅第5部分和第6部分。转至受管理对象模型文件,并使User → Task关系级联,如图1所示。
让我们创建一个具有两个todo 任务的 U ser ,如图2所示。如果您不理解此代码,请参阅第5部分和第6部分,其中我逐步讨论了该代码。 此代码将创建一个具有两个与之关联的待办事项的用户 ,并将其保存到磁盘
受管对象上下文视觉映射如图3所示。
通过仅向用户调用删除代码。 由于用户 → 任务删除规则是通过删除用户对象而级联的,因此它将删除与其相关联的所有任务 。 如您在控制台上看到的,没有任务对象剩余。
删除操作后的受管对象上下文的可视化映射如图4所示。您可以看到, 用户和与其关联的两个任务也从上下文中删除,并且通过调用save()方法,它也将从持久性存储中删除。
无效化
如果将关系的删除规则设置为Nullify ,则在删除记录时该关系的目标将无效,但目标对象仍然存在,仅源和目标之间的关系将被删除
首先将级联关系从下拉菜单更改为Nullify ,如图5所示。
让我们创建一个具有两个待办事项的U ser ,如图2所示。如果您不理解此代码,请参阅第5和第6部分,其中我逐步讨论了该代码。 此代码将创建一个具有两个与之关联的待办事项的用户 ,并将其保存到磁盘
托管对象上下文的可视化映射将如图6所示。
通过删除User对象,它不会删除与用户相关的任务,因为您可以看到我们仍添加在Managed Object Context中并打印在控制台中的两个任务,如图7所示。
托管对象上下文的可视化映射如图8所示。您可以看到因为User → Task具有相反的关系,在应用删除代码之前Task也引用了User对象。在删除User对象之后,此关系设置为nil如下所示
拒绝
如果关系目标(任务)上至少有一个对象,请不要删除源对象(用户)。
如果规则为Deny ,则在删除对象之前,必须从关系中删除一个或多个目标对象,否则在保存时会收到验证错误( 无法保存。Error Domain = NSCocoaErrorDomain Code = 1600 )。
在开始本节之前,首先删除应用程序并将一个任务添加到用户对象,如图9所示。
托管对象上下文的可视化映射将如图10所示。
当我们调用save()方法时,这些更改将保留在磁盘中。 持久性存储的可视化映射将如图11所示。
通过删除用户对象,由于一个任务对象仍与该用户对象相关联,因此不会删除用户 。 它将从托管对象上下文(内存)中删除User ,但是当我们调用save()方法将更改推送到持久性存储时,引发异常 ,如图12中的控制台所示。
删除操作后,托管对象上下文的可视映射将如图13所示。
持久性存储的可视化映射如图14所示。在物理存储中,它将具有其先前的状态,因为我们的save()方法由于Deny规则而引发Error。
现在,重新运行应用程序并打印用户对象。 由于我们的应用程序将首次启动,因此它将首先从持久性存储中将数据转储到NSManagedObjectContext缓存。 由于未从持久性存储中删除User对象,如图15所示,因此将User对象打印在控制台上,因为以前仅从内存中删除了该对象
要使用拒绝规则,我们需要先删除与该用户关联的所有任务,然后再删除User 。 该代码看起来如图16所示,并且没有错误。 您可以在NSManagedObject上使用validateForDelete来检查是否可以删除它。 现在,运行此代码后,持久性存储和托管对象上下文都具有相同的状态,不包含任何用户对象。
没有行动
对关系目标处的对象不执行任何操作。
例如,如果您删除一个用户,即使他们仍然认为所有任务属于该用户,也请保留所有任务。
故事
在我工作了将近四年的应用程序中,一位iOS新手开发了NoAction关系,然后我们使用Core Data加密对Core Data进行了加密。 我们的质量检查人员执行了应用程序更新方案,并且运行良好,当应用程序运行时,它在某些用户的更新上开始崩溃。 整整花了整整 三天的时间才弄清楚崩溃的原因,而罪魁祸首是NoAction 。 由于对象图的状态不一致,因此在迁移持久存储方法时崩溃。 现在在我们的应用程序中,我们没有NoAction删除规则。
没有动作规则可能有用,因为如果使用它,则有可能使对象图处于不一致状态(与删除的用户有关系的任务)。 让我们做一些编码,并通过可视化图了解它
首先转到CrudOperationCoreData.xcdatamodeld →点击用户实体→点击任务关系→在窗口右侧的Data Model Inspector上→选择Delete rule No Action ,如图17所示。
第一步,添加带有两个任务的 User并将其保存到持久性存储中,如图18所示。
托管对象上下文的可视化映射将如图19所示。
现在,当我们使用NSManagedObjectContext的delete()方法删除用户对象任务对象时。 如您所见,我们尚未调用save方法 ,如图20所示。
托管对象上下文的可视化映射如图21所示。您可以看到User对象仍存在于内存中,您可以使用expr lldb命令使用它们的引用来访问对象,如图22所示。 此外,上下文跟踪已删除对象数组中的已删除对象,并且当您在上下文上调用delete()方法时, 用户参考将存储在已删除对象数组上。
现在调用save()方法,它将使User对象出现故障,而task对象仍然引用不再存在的User Fault对象
调用save()方法后, 托管对象上下文和持久性存储的可视化映射如图23所示。
摘要
在第7部分中,我们借助编码和图表深入了解了删除规则。 我们讨论了Core数据提供的四种删除规则, Cascade和nullify起作用的情况占90%。
接下来是什么?
在下一部分中,我们将研究如何验证NSManagedObject。
有用的链接
https://cocoacasts.com/core-data-relationships-and-delete-rules
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1
https://iosdose.com/wp/2018/03/26/swift-core-data/
https://stackoverflow.com/questions/11990576/core-data-deny-delete-rule-causing-errors
https://stackoverflow.com/questions/5629481/xcode-consistency-error-setting-the-no-action-delete-rule-is-an-advanced-set
https://stackoverflow.com/questions/5629481/xcode-consistency-error-setting-the-no-action-delete-rule-is-an-advanced-set
https://cocoacasts.com/what-is-a-core-data-fault