Mac OS X Reference Library Apple Developer Connection spyglass button

Creating the Managed Object Model

This chapter specifies the Run entity and shows you how to create the managed object model. Although it is typically easiest to create the model in Xcode, in this tutorial you create the model entirely in code.

Xcode has a data modeling tool that you typically use to define the schema for your application (see Xcode Tools for Core Data for full details). The Xcode data modeling tool is analogous to Interface Builder in that it allows you to graphically create a complex collection of objects that are archived and at runtime are unarchived. Creating a user interface without Interface Builder is possible, but can require a lot of effort. Similarly, even a reasonably straightforward model requires a lot of code, so this tutorial only uses a single entity with two simple attributes. For more about creating a model using Xcode, see Creating a Managed Object Model with Xcode.

Specifying the Entity

The Run entity has two attributes, the process ID and the date on which the process was run. Neither attribute is optional—that is, each must have a value if an instance is to be considered valid (and if you try to save an instance without a value, you will get a validation error). The process ID has a default value of -1. In conjunction with the validation rules, this ensures that the value is properly set at runtime. You must also specify the class that will represent the entity in the utility—in this example you will use a custom class named “Run”.

Table 3-1  Attributes for the Run entity

Name

Type

Optional

Default Value

Minimum Value

date

date

NO

processID

int

NO

-1

0

Create the Managed Object Model

You could create the model in Xcode, put it in the application support directory, and load it at runtime using NSManagedObjectModel’s initWithContentsOfURL:. This example, however, illustrates how to create the model entirely in code.

Create the Model Instance

The first step is to create the managed object model instance itself, if necessary.

  1. At the top of the main source file, before main add a declaration for the function NSManagedObjectModel *managedObjectModel().

  2. In the main source file, implement the managedObjectModel function. It declares a static variable for the managed object model, and returns it immediately if it is not nil. If it is nil, create a new managed object model, then return it as the function result.

    NSManagedObjectModel *managedObjectModel() {
     
        static NSManagedObjectModel *mom = nil;
     
        if (mom != nil) {
            return mom;
        }
     
        mom = [[NSManagedObjectModel alloc] init];
        // implementation continues...
        return mom;
    }

You should enter the code described in the following sections, “Create the Entity” and “Add the Attributes,” immediately before the return statement (where the comment states, “implementation continues...”).

Create the Entity

The first step after creating the model itself, is to create the entity. You must set the name of the entity object before you add it to the model.

  1. Create the entity description object, set its name and managed object class name, and add it to the model as follows:

    NSEntityDescription *runEntity = [[NSEntityDescription alloc] init];
    [runEntity setName:@"Run"];
    [runEntity setManagedObjectClassName:@"Run"];
    [mom setEntities:[NSArray arrayWithObject:runEntity]];

Add the Attributes

Attributes are represented by instances of NSAttributeDescription. You must create two instances—one for the date, the other for the process ID—and set their characteristics appropriately. Both require a name and a type, and neither is optional. The process ID has a default value of -1. You also need to create a predicate for the process ID validation.

  1. Create the date attribute description object as follows. Its type is NSDateAttributeType and it is not optional.

    NSAttributeDescription *dateAttribute = [[NSAttributeDescription alloc] init];
     
    [dateAttribute setName:@"date"];
    [dateAttribute setAttributeType:NSDateAttributeType];
    [dateAttribute setOptional:NO];
  2. Create the process ID attribute description object as follows. Its type is NSInteger32AttributeType, it is not optional, and its default value is -1.

    NSAttributeDescription *idAttribute = [[NSAttributeDescription alloc] init];
     
    [idAttribute setName:@"processID"];
    [idAttribute setAttributeType:NSInteger32AttributeType];
    [idAttribute setOptional:NO];
    [idAttribute setDefaultValue:[NSNumber numberWithInteger:-1]];
  3. Create the validation predicate for the process ID. The value of the attribute itself must be greater than zero. The following code is equivalent to validationPredicate = [NSPredicate predicateWithFormat:@"SELF > 0"], but this example continues the theme of illustrating the long-hand form.

    NSExpression *lhs = [NSExpression expressionForEvaluatedObject];
    NSExpression *rhs = [NSExpression expressionForConstantValue:
                                            [NSNumber numberWithInteger:0]];
     
    NSPredicate *validationPredicate = [NSComparisonPredicate
                                            predicateWithLeftExpression:lhs
                                            rightExpression:rhs
                                            modifier:NSDirectPredicateModifier
                                            type:NSGreaterThanPredicateOperatorType
                                            options:0];
  4. Each validation predicate requires a corresponding error string. Typically the error string should be appropriately localized. You can either provide a localized representation here (using, for example, NSLocalizedString) or supply a localization dictionary for the model. The latter is shown in the next section (“Add a Localization Dictionary”). You provide the attribute description with an array of predicates and an array of error strings. In this case, each array contains just a single object.

    NSString *validationWarning = @"Process ID < 1";
    [idAttribute setValidationPredicates:[NSArray arrayWithObject:validationPredicate]
            withValidationWarnings:[NSArray arrayWithObject:validationWarning]];
  5. Finally, set the properties for the entity.

    NSArray *properties = [NSArray arrayWithObjects: dateAttribute, idAttribute, nil];
    [runEntity setProperties:properties];

Add a Localization Dictionary

You can set a localization dictionary to provide localized string values for entities, properties, and error strings related to the model. The key and value pattern is described in the API reference for setLocalizationDictionary:. The string you use as the key for the error must be the same as that you specified for the corresponding validation predicate.

NSMutableDictionary *localizationDictionary = [NSMutableDictionary dictionary];
 
[localizationDictionary setObject:@"Date" forKey:@"Property/date/Entity/Run"];
[localizationDictionary setObject:@"Process ID" forKey:@"Property/processID/Entity/Run"];
[localizationDictionary setObject:@"Process ID must not be less than 1" forKey:@"ErrorString/Process ID < 1"];
 
[mom setLocalizationDictionary:localizationDictionary];

Instantiate a Managed Object Model

So that you can test the implementation thus far, instantiate the managed object model and log its description of the model.

  1. In the main function, after the garbage collector is started, declare a variable of class NSManagedObjectModel and assign its value to the result of invoking the managedObjectModel function. Print the model description using NSLog.

    NSManagedObjectModel *mom = managedObjectModel();
    NSLog(@"The managed object model is defined as follows:\n%@", mom);

Build and Test

Build and run the utility. It should compile without warnings. The logged description of the model file should contain the entity and attributes you defined. Note that at this stage the model has not yet been used, so its isEditable state remains true.

Complete Listing

The complete listing of the managedObjectModel function is shown in Listing 3-1.

Listing 3-1  Complete listing of the managedObjectModel function

NSManagedObjectModel *managedObjectModel() {
 
    static NSManagedObjectModel *mom = nil;
 
    if (mom != nil) {
        return mom;
    }
 
    mom = [[NSManagedObjectModel alloc] init];
 
    NSEntityDescription *runEntity = [[NSEntityDescription alloc] init];
    [runEntity setName:@"Run"];
    [runEntity setManagedObjectClassName:@"Run"];
    [mom setEntities:[NSArray arrayWithObject:runEntity]];
 
    NSAttributeDescription *dateAttribute = [[NSAttributeDescription alloc] init];
 
    [dateAttribute setName:@"date"];
    [dateAttribute setAttributeType:NSDateAttributeType];
    [dateAttribute setOptional:NO];
 
 
    NSAttributeDescription *idAttribute = [[NSAttributeDescription alloc] init];
 
    [idAttribute setName:@"processID"];
    [idAttribute setAttributeType:NSInteger32AttributeType];
    [idAttribute setOptional:NO];
    [idAttribute setDefaultValue:[NSNumber numberWithInteger:-1]];
 
    NSExpression *lhs = [NSExpression expressionForEvaluatedObject];
    NSExpression *rhs = [NSExpression expressionForConstantValue:
                                        [NSNumber numberWithInteger:0]];
 
    NSPredicate *validationPredicate = [NSComparisonPredicate
                                            predicateWithLeftExpression:lhs
                                            rightExpression:rhs
                                            modifier:NSDirectPredicateModifier
                                            type:NSGreaterThanPredicateOperatorType
                                            options:0];
 
    NSString *validationWarning = @"Process ID < 1";
 
    [idAttribute setValidationPredicates:[NSArray arrayWithObject:validationPredicate]
        withValidationWarnings:[NSArray arrayWithObject:validationWarning]];
 
    NSArray *properties = [NSArray arrayWithObjects: dateAttribute, idAttribute, nil];
    [runEntity setProperties:properties];
 
    NSMutableDictionary *localizationDictionary = [NSMutableDictionary dictionary];
 
    [localizationDictionary setObject:@"Date"
                            forKey:@"Property/date/Entity/Run"];
    [localizationDictionary setObject:@"Process ID"
                            forKey:@"Property/processID/Entity/Run"];
    [localizationDictionary setObject:@"Process ID must not be less than 1"
                            forKey:@"ErrorString/Process ID < 1"];
 
    [mom setLocalizationDictionary:localizationDictionary];
 
    return mom;
}


Last updated: 2009-03-04

Did this document help you? Yes It's good, but... Not helpful...