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.
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”.
Name | Type | Optional | Default Value | Minimum Value |
|---|---|---|---|---|
date | date | NO | ||
processID | int | NO | -1 | 0 |
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.
The first step is to create the managed object model instance itself, if necessary.
At the top of the main source file, before main add a declaration for the function NSManagedObjectModel *managedObjectModel().
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...”).
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.
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]]; |
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.
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]; |
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]]; |
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]; |
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]]; |
Finally, set the properties for the entity.
NSArray *properties = [NSArray arrayWithObjects: dateAttribute, idAttribute, nil]; |
[runEntity setProperties:properties]; |
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]; |
So that you can test the implementation thus far, instantiate the managed object model and log its description of the model.
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 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.
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