Mastering In CoreData (Part 7 Core Data Relationships Delete Rules)

Core Data

As we discussed in part5 and part6 when we created Relationship between Entities. Every Entity NSManagedObject is associated with an entity description (an instance of NSEntityDescription) that provides metadata about the object. The object metadata includes the name of the entity that the object represents and the name of its attributes and relationships. There are a number of things you should consider when you create a relationship and delete rule is one of them.

Delete rule

Delete rules are one of the conveniences that make working with Core Data great. Every relationship has a delete rule. It defines what happens when the record that owns the relationship is deleted.

OR

A relationship’s delete rule specifies what should happen if an attempt is made to delete the source object.

In this part we will used our previous Entities to understand the deletion rule. Download the Todo application. First we will do some theory part then we will test it using actual coding

Core Data supports four delete rules → Cascade, Deny, Nullify, No Action.

Cascade

Delete the objects/object at the destination of the relationship when you delete the source. If we delete the user all tasks associated with the user will also be deleted

To add relationship between Entities see Part 5 and Part 6. Go to managed object model file and make the UserTask relationship cascade as shown in Figure 1

Figure 1

Let’s create User having two todo tasks as shown in Figure 2. If you don’t understand this code please see part 5 and 6 where I discussed this code step by step. This code will create a user having two todo tasks associated to it and saved it to the disk

Figure 2

Managed Object Context Visual Mapping is shown in Figure 3

Figure 3

By calling delete code to the user only. As the UserTask deletion rule is cascade by deleting User object it will delete all tasks associated to it. As you can see on the console no task object is remaining.

Visual Mapping of Managed Object Context after deletion operation is shown in Figure 4. As you can see User and two tasks associated to it are also deleted from the context and by calling save() method this will be deleted from the persistent store as well

Figure 4

Nullify

If the delete rule of a relationship is set to Nullify, the destination of the relationship is nullified when the record is deleted but destination object still persist only the relationship between source and destination is deleted

First change the cascade relationship to Nullify from drop down as shown in Figure 5

Figure 5

Let’s create User having two todo tasks as shown above in Figure 2. If you don’t understand this code please see part 5 and 6 where I discussed this code step by step. This code will create a user having two todo tasks associated to it and saved it to the disk

Visual Mapping of Managed Object Context will look like as shown in Figure 6

Figure 6

By deleting User object it will not delete tasks associated to the user as you can see two tasks that we added still in the Managed Object Context and printed in the console as well as shown in the Figure 7

Figure 7

Visual Mapping of Managed Object Context will look like as shown in Figure 8. As you can see the since UserTask has inverse relationship before delete code apply task also have a reference to User object.After deleted User object this relationship was set to nil as shown below

Figure 8

Deny

If there is at least one object at the relationship destination (Tasks), do not delete the source object (User).

If a rule is Deny, then before you delete an object you must remove the destination object or objects from the relationship, otherwise you will get a validation error (Could not save. Error Domain=NSCocoaErrorDomain Code=1600) when you save.

Before go the this section first delete the application and add one task to the user object as shown in Figure 9

Figure 9

Visual Mapping of Managed Object Context will look like as shown in Figure 10

Figure 10

When we call save() method these changes will persist into the disk. Visual Mapping of Persistent Store will look like as shown in Figure 11

Figure 11

By deleting User object it will not delete User since one task object still associated to the User object. It will delete the User from managed object context (memory) but when we will call save() method to push changes to persistent store Exception raised as shown in the console in Figure 12

Figure 12

Visual Mapping of Managed Object Context will look like as shown in Figure 13 after delete operation

Figure 13

Visual Mapping of Persistent store will look like as shown in Figure 14. In physical storage it will have their previous state since our save() method throw an Error because of the Deny rule.

Figure 14

Now rerun application and print User objects. Since our application will launch first time it will first dump data from the persistent store to NSManagedObjectContext Cache. Since User object was not deleted from the persistent store as shown in Figure 15 User object was printed on the console since previously it was only deleted from memory

Figure 15

To work with Deny rule we need to delete all tasks associated tothe user first then delete User . The code looks like this as shown in Figure 16 and worked with no error. You can use validateForDelete on NSManagedObject to check if it can be deleted or not. Now after running this code Persistent store and Managed object context both have the same state contains no User object.

Figure 16

No Action

Do nothing to the object at the destination of the relationship.

For example, if you delete a User, leave all the tasks as they are, even if they still believe they belong to that user.

Story

In the application that I worked almost four years one of our developers who was new to the iOS made one of the relationship NoAction and after we encrypted our Core Data using Core Data encryption. Our QA performed application update scenario and it was working fine and when the application was live it started crashing on update on some users. It took three complete days and night to figured out the crash and the culprit was NoAction. It was crashing on migration of persistent store method because of the inconsistent state of the object graph. Now in our application we don’t have NoAction delete rule.

No Action rule might be of use, because if you use it, it is possible to leave the object graph in an inconsistent state (tasks having a relationship to a deleted user). Let’s do some coding and understand it with visual diagram

First Go to to the CrudOperationCoreData.xcdatamodeld → Tap on User Entity → Tap on tasks relationship → On the Data Model Inspector right side of the window → select Delete rule No Action as shown in Figure 17

Figure 17

First step to add User with two tasks and save it to the persistent store as shown in Figure 18

Figure 18

Visual Mapping of Managed Object Context will look like as shown in Figure 19

Figure 19

Now when we delete the User object task object using delete() method of NSManagedObjectContext. As you can see we didn’t call save method yet as shown in figure 20

Figure 20

Visual Mapping of Managed Object Context will look like as shown in Figure 21. As you can see User object still present in memory you can access objects using their reference as shown in Figure 22 by using expr lldb command. Also context track deleted objects in deleted Objects array and when you call the delete() method on context User reference will store on deleted objects array.

Figure 21

Now calling save() method and it will make the User objects faulty and tasks objects still referencing to the User faulty objects which is no longer exists

Figure 22

Visual Mapping of Managed Object Context and Persistent store will look like as shown in Figure 23 after calling save() method

Figure 23

Summary

In this part 7 we looked the delete rule in depth with the help of coding and diagrams. we discussed four delete rule Core data provides and 90% od the case Cascade and nullify worked.

What Next?

In the next part we will look how to validate NSManagedObject.

Useful Links

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

Senior iOS Engineer | HungerStation | Delivery Hero