Leave a rating/review
When you delete an instance of managed object in Core Data it matters how complex your object graph is. Let’s say your app just had RocketLaunches and nothing else. Then deleting a RocketLaunch is really simple and you can delete individual items without any concerns.
But let’s say your model contains managed objects like RocketLaunch, RocketLaunchList and Tag.
Over time you create instances and instantiate objects in your graph and it now looks like this. There are several launches in many lists and you’ve added a variety of tags to each. What happens if you delete a List - what happens to the associated launches? Should they get deleted as well?
RocketLaunches are associated with a list so maybe it makes sense to just get rid of them, but what about tags? If you delete a launch that tag might still be associated with another launch? How do you know when it’s appropriate to delete the tag? Don’t worry Core Data has thought of this already.
All Core Data relationships specify a delete rule that governs what should happen if you attempt to delete a source object. Let’s go over each one and you’ll use an example of a relationship between a RocketLaunch and a Tag.
In this example the RocketLaunch is the source object and the Tag is the destination. A RocketLaunch can have any number of tags, and a tag can be associated with any number of RocketLaunches so this is a One to Many relationship in both directions - or a Many to Many, which is what the double arrow heads in both directions indicate.
First up is the Deny rule. With the Deny rule, if there is at least one object at the relationship destination then you cannot delete the source object.
With the deny rule, if you tried to delete a RocketLaunch that had an associated tag you wouldn’t be able to. You would need to ensure that either all associated tags are deleted first, or that you have removed the association.
Next up is the nullify rule. If you delete a launch with the nullify rule set, then the relationship between the objects is deleted, but neither the reminder nor the tag are deleted. Nullify relationships are useful if the relationship in both directions are optional.
There is a fair bit of confusion around the nullify rule and as a result a pretty long standing misconception. If you scour the internet you’ll see most people saying that nullify not only deletes the relationship between the source and destination objects but the objects themselves.
But, as the documentation clearly states, nullify only deletes the relationship, leaving both the source and destination object intact.
After that you have the cascade rule. With the cascade rule in place if you delete a source object, then the object at the destination of the relationship is also deleted. This would mean that if you deleted a launch it would delete all the associated tags as well.
Finally you have the no action rule. This is pretty much what is sounds like - when you delete an object do nothing to the object at the destination of the relationship.
So which one do you chose for your data model? Let’s think about it.
If you have a List with a couple of launches and you delete the list, what do you think should happen? You have two options:
-
The lists should not be deleted if they have associated launches with it. At first glance that seems like a reasonable approach but if you think about it, that condition will never be true. Right now when you mark a launch as viewed, you don’t get rid of it, you just don’t fetch and display it. Even on a list where all launches are viewed, they are all still associated with that list. If you wanted to only allow for deleting a list if there are no launches associated then you would have to refactor the app to actually delete launches that are viewed.
-
Your second option is to delete all associated launches when a list is deleted. This is how the iOS Reminders app is modeled. If you create a new list and add a reminder, when attempting to delete that list you get an alert indicating that all associated reminders will be deleted as well.
Let’s go with this approach. To delete all launches when a list is deleted you’re going to set the delete rule to Cascade.
But what about in the other direction. Remember that these rules talk about a source and destination object and all relationships are bidirectional. Ok so what happens when you delete a launch? Let’s walk through each rule:
-
Deny. For deny to make sense the only time you could delete a launch is if the list were already deleted. Given that deleting a List automatically deletes the reminders this doesn’t make sense
-
What about nullify? Well nullify would delete the relationship but still leave the launch around. You don’t want that either.
-
Cascade is off the table immediately. You don’t want to delete the list when just one reminder is deleted.
That leaves you with No Action. When you delete a launch you don’t do anything to the list. That sounds great. You’ve already set up your list such that it can exist without any launches associated with it. If you hadn’t done that and the launches relationship was required, then that would be an issue.
There is a catch to No Action that you should be aware of. If you use the No Action rule, it is up to you to ensure that the consistency of the object graph is maintained which would mean setting any inverse relationship to a meaningful value.
Now that you know about the various rules, let’s implement them so we can actually delete items.