掌握CoreData(第7部分核心数据关系删除规则)

正如我们在第5部分和第6部分中讨论的,当我们创建实体之间的关系时。 每个实体NSManagedObject与一个实体描述(NSEntityDescription的一个实例)相关联,该实体描述提供有关对象的元数据。 对象元数据包括对象代表的实体的名称以及其属性和关系的名称。 创建关系时,应考虑许多事项,删除规则就是其中之一。

删除规则

删除规则是使用Core Data的一大便利。 每个关系都有删除规则。 它定义了删除拥有关系的记录时发生的情况。

要么

关系的删除规则指定了尝试删除源对象时应该发生的情况。

在这一部分中,我们将使用之前的实体来了解删除规则。 下载Todo应用程序。 首先我们将做一些理论上的部分,然后我们将使用实际编码对其进行测试

核心数据支持四种删除规则:“层叠”,“拒绝”,“无效”和“不执行操作”。

级联

删除源时,请删除关系目标处的对象。 如果我们删除用户,则与该用户关联的所有任务也将被删除

要添加实体之间的关系,请参阅第5部分和第6部分。转至受管理对象模型文件,并使UserTask关系级联,如图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所示。您可以看到因为UserTask具有相反的关系,在应用删除代码之前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数据提供的四种删除规则, Cascadenullify起作用的情况占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