Creating and Deleting Managed Objects

The Core Data Framework relieves you from the need to implement many of the mechanisms needed to manage data-bearing (model) objects. It does, though, impose the requirement that model objects are instances of, or instances of classes that inherit from, NSManagedObject, and that the model objects are properly integrated in to the Core Data infrastructure. This document first describes the basic pieces of the infrastructure you need to create a managed object, and how to easily instantiate an instance of a managed object and integrate it into that infrastructure. It then describes the processes that are abstracted by the convenience methods you typically use to create a managed object; how to assign an object to a particular store; and finally how to delete a managed object.

Creating, Initializing, and Saving a Managed Object

A managed object is an instance of an Objective-C class. From this perspective, it is no different from any other object you use—you can simply create an instance using alloc. A managed object differs from other objects in three main ways—a managed object:

In principle, there is therefore a lot of work to do to create a new managed object and properly integrate it into the Core Data infrastructure. In practice, however, this task is made easy by a convenience class method (insertNewObjectForEntityForName:inManagedObjectContext:) of NSEntityDescription. The following example shows the easiest way to create a new instance of an entity named “Employee”.

NSManagedObject *newEmployee = [NSEntityDescription
    insertNewObjectForEntityForName:@"Employee"
    inManagedObjectContext:context];

The method returns an instance of whatever class is defined in the managed object model to represent the entity, initialized with the default values given for its entity in the model.

In many cases the default values you set in the model may be sufficient. Sometimes, however, you may wish to perform additional initialization—perhaps using dynamic values (such as the current date and time) that cannot be represented in the model. In a typical Cocoa application you would override the class’s init method to provide this functionality. With NSManagedObject, you are discouraged from overriding initWithEntity:insertIntoManagedObjectContext:; instead, Core Data provides several other means of initializing values—these are described in “Object Life-Cycle—Initialization and Deallocation.”

Simply creating a managed object does not cause it to be saved to a persistent store. The managed object context acts as a scratchpad. You can create and register objects with it, make changes to the objects, and undo and redo changes as you wish. If you make changes to managed objects associated with a given context, those changes remain local to that context until you commit the changes by sending the context a save: message. At that point—provided that there are no validation errors—the changes are committed to the store.

See also “Assigning an Object to a Store.”

Behind the Scenes of Creating a Managed Object

Although NSEntityDescription’s convenience method makes it easy to create and configure a new managed object, it may be instructive to detail what is happening behind the scenes. If this is not of current interest, you may safely skip this section (go to “Assigning an Object to a Store”)—you are encouraged, however, to revisit this material to ensure that you fully understand the process.

In order to properly integrate a managed object into the Core Data infrastructure there are two elements you need:

The Managed Object Context

The context is responsible for mediating between its managed objects and the rest of the Core Data infrastructure. The infrastructure is in turn responsible for, for example, translating changes to managed objects into undo actions maintained by the context, and also into operations that need to be performed on the persistent store with which the managed object is assigned.

The context is in effect also your gateway to the rest of the Core Data infrastructure. As such, it is expected that you either keep a reference to the context, or you have a means of easily retrieving it—for example, if you are developing a document-based application that uses NSPersistentDocument, you can use the document class’s managedObjectContext method.

The Entity Description

An entity description specifies (amongst other things) the name of an entity, the class used to represent the entity, and the entity’s properties. The entity description is important since a given class may be used to represent more than one entity—by default all entities are represented by NSManagedObject. Core Data uses the entity description to determine what properties a managed object has, what needs to be saved to or retrieved from the persistent store, and what constraints there are on property values. Entity descriptions are properties of a managed object model.

Given a managed object context, you could retrieve the appropriate entity description through the persistent store coordinator as illustrated in the following example:

NSManagedObjectContext *context = <#Get a context#>;
NSManagedObjectModel *managedObjectModel =
    [[context persistentStoreCoordinator] managedObjectModel];
NSEntityDescription *employeeEntity =
    [[managedObjectModel entitiesByName] objectForKey:@"Employee"];

In practice, you would use the convenience method entityForName:inManagedObjectContext: of NSEntityDescription which does the same thing—as illustrated in the following example:

NSManagedObjectContext *context = /* assume this exists */;
NSEntityDescription *employeeEntity = [NSEntityDescription
            entityForName:@"Employee"
            inManagedObjectContext:context];

Creating a Managed Object

Fundamentally NSManagedObject is an Objective-C class like any other Objective-C class. Like various other classes, NSManagedObject imposes some constraints on instance creation. As described earlier, you must associate the new managed object instance with the entity object that defines its properties and with the managed object context that defines its environment. You cannot therefore initialize a managed object simply by sending an init message, you must use the designated initializer—initWithEntity:insertIntoManagedObjectContext:—which sets both the entity and context:

NSManagedObject *newEmployee = [[NSManagedObject alloc]
            initWithEntity:employeeEntity
            insertIntoManagedObjectContext:context];

This is in effect what NSEntityDescription’s convenience method insertNewObjectForEntityForName:inManagedObjectContext: does for you—including the entity instance look-up described in “The Entity Description.” This is why you should typically use that method rather than NSManagedObject’s initWithEntity:insertIntoManagedObjectContext:.

An important additional point here is that initWithEntity:insertIntoManagedObjectContext: returns an instance of the class specified by the entity description to represent the entity. If you want to create a new Employee object and in the model you specified that the Employee entity should be represented by a custom class, say Employee, it returns an instance of Employee. If you specified that the Employee entity should be represented by NSManagedObject, it returns an instance of NSManagedObject.

Assigning an Object to a Store

Typically there is only one persistent store for a given entity, and Core Data automatically ensures that new objects are saved to this store when the object's managed object context is saved. Sometimes, however, you may have multiple writable stores for a given entity—for example you may store some data in a specific document and some in a common global repository (say, a store in the user’s Application Support folder). In this situation you must specify the store in which the object is to reside.

You specify the store for an object using the NSManagedObjectContext method, assignObject:toPersistentStore:. This method takes as its second argument the identifier for a store. You obtain the store identifier from the persistent store coordinator, using for example persistentStoreForURL:. The following example illustrates the complete process of creating a new managed object and assigning it to a global store.

NSURL *storeURL = <#URL for path to global store#>;
 
id globalStore = [[context persistentStoreCoordinator]
    persistentStoreForURL:storeURL];
 
NSManagedObject *newEmployee = [NSEntityDescription
    insertNewObjectForEntityForName:@"Employee"
    inManagedObjectContext:context];
 
[context assignObject:newEmployee toPersistentStore:globalStore];

Of course, the object is not saved to the store until the managed object context is saved.

Deleting a Managed Object

Deleting a managed object is straightforward. You simply send its managed object context a deleteObject: message, passing the object you want to delete as the argument.

[aContext deleteObject:aManagedObject];

This removes the managed object from the object graph. Just as a new object is not saved to the store until the context is saved, a deleted object is not removed from the store until the context is saved.

Relationships

When you delete a managed object it is important to consider its relationships and in particular the delete rules specified for the relationships. If all of a managed object's relationship delete rules are Nullify, then for that object at least there is no additional work to do (you may have to consider other objects that were at the destination of the relationship—if the inverse relationship was either mandatory or had a lower limit on cardinality, then the destination object or objects might be in an invalid state). If a relationship delete rule is Cascade, then deleting one object may result in the deletion of others. 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 when you save. If a delete rule is No Action, then you must ensure that you take whatever steps are necessary to ensure the integrity of the object graph. For more details, see “Relationship Delete Rules.”

Deleted status and notifications

You can find out if a managed object has been marked for deletion by sending it an isDeleted message. If the return value is YES, this means that the object will be deleted during the next save operation, or put another way, that the object is marked deleted for the current (pending) transaction. In addition, when you send a managed object context a deleteObject: message, the context posts a NSManagedObjectContextObjectsDidChangeNotification notification that includes the newly-deleted object in its list of deleted objects. Note, however, that an object being marked for deletion from a context is not the same as its being marked for deletion from a persistent store. If an object is created and deleted within the same transaction—that is, without an intervening save operation—it will not appear in the array returned by NSManagedObjectContext's deletedObjects method or in the set of deleted objects in a NSManagedObjectContextDidSaveNotification notification.