How to handle external data wipe when deleting Core Data objects

I am new to Core Data and have run into a problem that others have encountered.

My data model includes images, and I keep them external to the database and just keep the path / URL to the image. (as recommended in one of the Apple Core Data presentations)

When deleting my image object, I can manually go around the relationships and delete the image files, but I'm wondering if there is a more elegant way to do this.

The ideal solution will somehow be tied to the image object and will work with Core Data undo / redo.

+6
ios iphone core-data
source share
4 answers

In your "image" object class, execute willSave . Check [self isDeleted] and delete the file, if so. This delays the actual deletion of the file until the storage is saved, giving you some cancellation. Set up appropriate cascading rules to remove image objects when their owner leaves and there you go.

[eta: Phil Calvin's comment below on the right - didSave is probably the best place if you use multiple contexts.]

[ETA. much later:] MartinW raises an excellent point - if the object has never been saved, it will / will not be saved. Deleting an unsaved object simply does not insert it from the context and throws it out without special life cycle events. And just to complicate matters more, you can “cancel” and “redo” the deletion, including (I think) of this kind.

A few considerations that come to mind:

This might be the case of an override of prepareForDeletion: plus awakeFromSnapshotEvents: to catch the deletion and re-deletion. To support undo / redo, you don’t just need to delete the file in place, but use some kind of registry “for deletion” (for example, a common changed set of file names to clean when a save notification is sent). Then / didSave will be taken out of the image.

Or, if you can live with BLOB fields instead of files, you can check the "allows external storage" field on a binary property, put jpeg data there and get some (not all) advantages of storing files without (most of) headaches. A small binary will be stored in db; something more than a private threshold will be disconnected into a separate hidden data-driven file. However, the main data still needs to load all of this into NSData if the object crashes. I use this approach for small user avatar images.

Finally, if nothing else is stored in the images directory, you can register for didSave notifications and manually clear it after saving. Run a selection request for all Image.filename properties, compare it with the list of directories with the dir image in the question, delete it if necessary. I use this approach as my “big stick” during development to make sure that everything else does what it needs.

[Let me know of successes or difficulties with these approaches, and I will keep this in the know.]

+13
source share

In your Image class, run -didSave . In this method, check if [self isDeleted] and if it is YES , delete files from disk from disk.

This is important to do in -didSave , not -willSave , especially if you have several managed object contexts associated with your persistent storage. willSave sent before Core Data detects and reports (as a save error) any merge conflicts. This means that you could get willSave :

  • Several times if you are implementing a merge strategy that combines objects and repeatedly tries to save
  • Before saving, which is never committed to persistent storage due to merge conflict

Deleting image files can fail prematurely later when these images are accessed from a different context of the managed entity.

+4
source share

I would suggest overriding prepareForDeletion image prepareForDeletion to remove the image file on disk. The method will be called only with the object of the image object, which is actually deleted.

+2
source share

Best practice would be (which, I think, would be the same with what @Rog meant) to have an entity for saved images and make your objects linked to that object, rather than saving paths in each object. In this case, you can simply find one object that represents the image that you want to delete and delete it, otherwise the reverse relationship may be automatically canceled.

0
source share

All Articles