Managed Objects

This article provides basic information about what is a managed object, how its data is stored, how you implement a custom managed object class, object life-cycle issues, and faulting. There are several other articles in the Core Data Programming Guide that describe other aspects of using managed objects:

Basics

Managed objects are instances of the NSManagedObject class, or of a subclass of NSManagedObject, that represent instances of an entity. NSManagedObject is a generic class that implements all the basic behavior required of a managed object. You can create custom subclasses of NSManagedObject, although this is often not required. If you do not need any custom logic for a given entity, you do not need to create a custom class for that entity. You might implement a custom class, for example, to provide custom accessor or validation methods, to use non-standard attributes, to specify dependent keys, to calculate derived values, or to implement any other custom logic.

A managed object is associated with an entity description (an instance of NSEntityDescription) that provides metadata about the object (including the name of the entity that the object represents and the names of its attributes and relationships) and with a managed object context that tracks changes to the object graph.

A managed object is also associated with a managed object context (“context”). In a given context, a managed object provides a representation of a record in a persistent store. In a given context, for a given record in a persistent store, there can be only one corresponding managed object, but there may be multiple contexts each containing a separate managed object representing that record. Put another way, there is a to-one relationship between a managed object and the data record it represents, but a to-many relationship between the record and corresponding managed objects.

Properties and Data Storage

In some respects, an NSManagedObject acts like a dictionary—it is a generic container object that efficiently provides storage for the properties defined by its associated NSEntityDescription object. NSManagedObject provides support for a range of common types for attribute values, including string, date, and number (see NSAttributeDescription for full details). There is therefore commonly no need to define instance variables in subclasses. There are some performance considerations to bear in mind if you use large binary data objects—see “Large Data Objects (BLOBs).”

Non-Standard Attributes

NSManagedObject provides support for a range of common types for attribute values, including string, date, and number (see NSAttributeDescription for full details). By default, NSManagedObject stores its properties as objects in an internal structure, and in general Core Data is more efficient working with storage under its own control rather than using custom instance variables.

Sometimes you want to use types that are not supported directly, such as colors and C structures. For example, in a graphics application you might want to define a Rectangle entity that has attributes color and bounds that are an instance of NSColor and an NSRect struct respectively. This may require you to create a subclass of NSManagedObject, and is described in “Non-Standard Persistent Attributes.”

Dates and Times

NSManagedObject represents date attributes using NSDate objects, and stores times internally as an NSTimeInterval value since the reference date (which has a time zone of GMT). Time zones are not explicitly stored—indeed you should always represent a Core Data date attribute in GMT, this way searches are normalized in the database. If you need to preserve the time zone information, you need to store a time zone attribute in your model. This may again require you to create a subclass of NSManagedObject.

Custom Managed Object Classes

In combination with the entity description in the managed object model, NSManagedObject provides a rich set of default behaviors including support for arbitrary properties and value validation. There are nevertheless many reasons why you might wish to subclass NSManagedObject to implement custom features. There are also, however, some things to avoid when subclassing. It’s also important to be aware that Core Data manages the life-cycle of modeled properties.

Overriding Methods

NSManagedObject itself customizes many features of NSObject so that managed objects can be properly integrated into the Core Data infrastructure. Core Data relies on NSManagedObject’s implementation of the following methods, which you should therefore not override: primitiveValueForKey:, setPrimitiveValue:forKey:, isEqual:, hash, superclass, class, self, zone, isProxy, isKindOfClass:, isMemberOfClass:, conformsToProtocol:, respondsToSelector:, managedObjectContext, entity, objectID, isInserted, isUpdated, isDeleted, and isFault. You are discouraged from overriding description—if this method fires a fault during a debugging operation, the results may be unpredictable—and initWithEntity:insertIntoManagedObjectContext:. You should typically not override the key-value coding methods such as valueForKey: and setValue:forKeyPath:.

In addition to methods you should not override, there are others that if you do override you should invoke the superclass’s implementation first, including awakeFromInsert, awakeFromFetch, and validation methods such as validateForUpdate:.

Modeled Properties

Core Data dynamically generates efficient public and primitive get and set attribute accessor methods and relationship accessor methods for properties that are defined in the entity of a managed object’s corresponding managed object model. Typically, therefore, you don’t need to write custom accessor methods for modeled properties.

In a managed object sub-class, you can declare the properties for modeled attributes in the interface file, but you don’t declare instance variables:

@interface MyManagedObject : NSManagedObject
 
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSDate *date;
@end

Notice that the properties are declared as nonatomic, and strong. For performance reasons, Core Data typically does not copy object values, even if the value class adopts the NSCopying protocol.

In the implementation file, you specify the properties as dynamic:

@implementation MyManagedObject
@dynamic title;
@dynamic date;
@end

If you do need to implement custom accessor methods, there are several implementation patterns you must follow—see “Managed Object Accessor Methods.”

Object Life-Cycle—Initialization and Deallocation

Core Data “owns” the life-cycle of managed objects. With faulting and undo, you cannot make the same assumptions about the life-cycle of a managed object as you would of a standard Cocoa object—managed objects can be instantiated, destroyed, and resurrected by the framework as it requires.

When a managed object is created, it is initialized with the default values given for its entity in the managed object model. In many cases the default values 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 class, you usually override the designated initializer (often the init method). In a subclass of NSManagedObject, there are three different ways you can customize initialization —by overriding initWithEntity:insertIntoManagedObjectContext:, awakeFromInsert, or awakeFromFetch. You should not override init. You are discouraged from overriding initWithEntity:insertIntoManagedObjectContext: as state changes made in this method may not be properly integrated with undo and redo. The two other methods, awakeFromInsert and awakeFromFetch, allow you to differentiate between two different situations:

You should typically not override dealloc to clear transient properties and other variables. Instead, you should override didTurnIntoFault. didTurnIntoFault is invoked automatically by Core Data when an object is turned into a fault and immediately prior to actual deallocation. You might turn a managed object into a fault specifically to reduce memory overhead (see “Reducing Memory Overhead”), so it is important to ensure that you properly perform clean-up operations in didTurnIntoFault.

Validation

NSManagedObject provides consistent hooks for validating property and inter-property values. You typically should not override validateValue:forKey:error:, instead you should implement methods of the form validate<Key>:error:, as defined by the NSKeyValueCoding protocol. If you want to validate inter-property values, you can override validateForUpdate: and/or related validation methods.

You should not call validateValue:forKey:error: within custom property validation methods—if you do so you will create an infinite loop when validateValue:forKey:error: is invoked at runtime. If you do implement custom validation methods, you should typically not call them directly. Instead you should call validateValue:forKey:error: with the appropriate key. This ensures that any constraints defined in the managed object model are applied.

If you implement custom inter-property validation methods (such as validateForUpdate:), you should call the superclass’s implementation first. This ensures that individual property validation methods are also invoked. If there are multiple validation failures in one operation, you should collect them in an array and add the array—using the key NSDetailedErrorsKey—to the userInfo dictionary in the NSError object you return.

Faulting

Managed objects typically represent data held in a persistent store. In some situations a managed object may be a “fault”—an object whose property values have not yet been loaded from the external data store—see “Faulting and Uniquing” for more details. When you access persistent property values, the fault “fires” and the data is retrieved from the store automatically. This can be a comparatively expensive process (potentially requiring a round trip to the persistent store), and you may wish to avoid unnecessarily firing a fault (see “Faulting Behavior”).

Although the description method does not cause a fault to fire, if you implement a custom description method that accesses the object’s persistent properties, this will cause a fault to fire. You are strongly discouraged from overriding description in this way.

There is no way to load individual attributes of a managed object on an as-needed basis. For patterns to deal with large attributes, see “Large Data Objects (BLOBs).”