删除* unsaved * Core Data对象时如何处理外部数据的清理?

时间:2014-09-01 09:56:30

标签: cocoa core-data nsmanagedobject nsmanagedobjectcontext

在托管对象中,我已经存储了应用程序容器中图像文件的路径 删除托管对象后,应将图像文件移至废纸篓。这应该尽可能晚地完成,这样我就可以尽可能长时间地提供撤销功能。

我正在关注这个问题的答案:How to handle cleanup of external data when deleting Core Data objects,并且在我的托管对象子类中覆盖了-didSave以废弃文件。

事实证明,这只适用于:

  • 已添加托管对象
  • 已保存托管对象上下文
  • 已删除托管对象
  • 保存托管对象上下文。

在以下情况中,但是在托管对象中未调用-isSaved:

  • 已添加托管对象
  • 已删除托管对象
  • 保存托管对象上下文。

我明白为什么会这样。由于删除的对象从未在第一个地方持久存在,因此在删除后不会保存它,也不会调用-didSave。

现在我正在寻找另一个将引用文件移动到垃圾箱的地方。那可能在哪里?

2 个答案:

答案 0 :(得分:9)

如何使用托管对象方法实现此操作有两种选择:使用托管对象生命周期事件,或使用验证。 但是,这样做有一些权衡和风险还有其他方法可能对你更有效(见建议)。

管理对象生命周期

托管对象由拥有它们的NSManagedObjectContext观察。这是托管对象中的“托管”。 NSManagedObject实例的大部分内容实际上由NSManagedObjectContext执行。托管对象为informed of changes through the life cycle event methodsawakeFromFetchawakeFromInsertawakeFromSnapshotEvents:didSavedidTurnIntoFaultprepareForDeletion等。在这些方法中,您必须小心不要以在上下文中将其标记为“脏”的方式更改托管对象,否则将更改当前事务。例如,尝试在didSave中“复活”已删除的对象,或更改awakeFromFetch中的关系,或访问didTurnIntoFault中的属性(这会触发错误,这会很糟糕)

在典型删除已保存对象的过程中,将按以下顺序调用生命周期事件:

如果随后在对象的父上下文中完成了保存,则在这些上下文拥有的实例上可能会发生其他生命周期事件。在处理Core Data之外的共享资源时,请记住这一点非常重要。

当一个对象尚未保存并从上下文中删除时,生命周期事件按此顺序发生:

在这种情况下,使用托管对象生命周期方法可能不是一个好的解决方案。如您所见,prepareForDeletion在您感兴趣的场景中被调用 - 但是在保存操作的情况下验证删除之前就会发生。{/ p>

验证

验证是一项重要的核心数据功能。保存对象时,Core Data会应用模型中设置的验证规则以及NSManagedObject类中实现的任何自定义验证。在删除的情况下,Core Data应用模型中定义的删除规则作为保存操作的一部分。在验证发生之前调用 { - 1}} - 因此,如果您将数据作为prepareForDeletion的一部分进行删除,则可能会删除实际上不会被删除的对象的数据一个保存。这可能会给你带来一些问题。

您可以将删除作为prepareForDeletion的一部分实现,也可以作为自定义验证方法来检查对象的状态(validateForDelete:isDeleted等)。 isInserted的超级实现将执行删除规则,请务必适当调用它。验证将作为保存操作的一部分自动调用 ,但您可以随时手动调用(建议这样做)。要手动执行验证,请从您的应用程序中调用适当的方法,在本例中为validateForDelete:。检查BOOL结果,如果返回NO,则适当处理错误。

推荐

最好将图像数据写入本地文件系统,作为验证或保存的一部分。当Core Data执行保存时,它实际上将上下文中的所有更改作为事务提交。在处理外部资源时,对同一进程中的外部资源进行提交更改是很有意义的。例如,在validateForDelete:方法中,您至少应验证给定的URL是本地文件系统URL,并且您可以写入它。在validateImageURL:error: / willSave中,如果已插入或更新对象,您可以写入didSave指定的URL,如果已删除,则删除imageURL处的数据。对于尚未保存但正从上下文中删除的对象,数据尚未提交到本地文件系统。它只会存在于内存中,就像与该对象相关的所有其他内容一样。

请注意,无论您如何实现外部数据的读取,写入和删除,都应使用NSFileCoordinator APIs来协调对文件和目录的访问。

这种方法仍然存在问题。 imageURL(及其对象)只是对持久性存储中的数据的引用的集合。如果要从NSManagedObjectContext保存外部数据,当有多个上下文,嵌套上下文(您应该使用它们等等)时,可能会遇到问题.NSPersistentStore管理{{1的持久性数据,理想情况下,您与文件系统的交互将发生在该级别 - 这将解决我提到的一些问题以及更多问题。 最好的方法是使用Core Data的外部存储功能来管理这些数据,因为它已经内置到(某些)持久存储中。 您还可以尝试子类化NSManagedObject并覆盖方法NSManagedObject以实现您自己的外部存储。

答案 1 :(得分:1)

非常好 - 我也在这个问题上更新了我的答案,我将在这里扩展我最喜欢的方法:

  1. 忘记遗嘱/保存。在这种情况下不可靠。

  2. 实施prepareForDeletion:。如果您不需要撤消,并确保删除成功,请立即删除该文件。否则,将文件添加到方便的注册表(上下文所有者拥有的NSMutableSet或其他一些注册表。)

  3. 如果您确实需要撤消/重做,请实施awakeFromSnapshotEvents:以捕获未删除和重新删除。根据需要从/向注册表中删除/重新添加文件。

  4. 在方便的地方注册didSave通知。保存发生时,删除注册表中列出的所有文件并清除它。

  5. 顺便说一下,所有这些都假设您拥有的对象中没有两个拥有相同的文件。如果这是一种可能性,事情变得更加复杂 - 但我想你已经专门设置了你的模型以避免这种情况发生。