Wednesday, July 17, 2013

Core Data Programming Guide Notes -- Part 1

This is the notes of Core Data Programing Guide from reading Apple's document

reference: http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Conceptual/CoreData/cdProgrammingGuide.html#//apple_ref/doc/uid/TP30001200-SW1


Why Should You Use Core Data?
  50% to 70% smaller as measured by lines of code 

  Core Data has a mature code base whose quality is maintained 

  Core Data integrates well with the OS X tool chain 



What Core Data Is Not
Core Data is not a relational database or a relational database management system (RDBMS). 

Core Data is not a silver bullet.
Core Data does not rely on Cocoa bindings.



Basic Core Data Architecture



Managed Objects and Contexts

You can think of a managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad where they form an object graph (or a collection of object graphs). You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered. 


Model objects that tie into in the Core Data framework are known as managed objects. All managed objects must be registered with a managed object context.



Fetch Requests 

To retrieve data using a managed object context, you create a fetch request. A fetch request is an object that specifies what data you want, for example, “all Employees,” or “all Employees in the Marketing department ordered by salary, highest to lowest.”  



Persistent Store Coordinator
Between managed object contexts and persistent object stores there is a persistent store coordinator. 


Persistent Documents
The NSPersistentDocument class is a subclass of NSDocument that is designed to let you easily take advantage of the Core Data framework. By default, an NSPersistentDocument instance creates its own ready-to-use persistence stack, including a managed object context and a single persistent object store. There is in this case a one-to-one mapping between a document and an external data store. 



Managed Objects and the Managed Object Model
A managed object model is a schema that provides a description of the managed objects, or entities, used by your application





Managed objects must be instances of either NSManagedObject or of a subclass of NSManagedObject. NSManagedObject is able to represent any entity.


Managed Object Models

he schema is represented by a managed object model—an instance of NSManagedObjectModel. In general, the richer the model, the better Core Data is able to support your application. 


Features of a Managed Object Model 

A managed object model is an instance of the NSManagedObjectModel class

Entities
A model contains NSEntityDescription objects that represent the model's entities. Two important features of an entity are its name, and the name of the class used to represent the entity at runtime. 


Entity Inheritance



Abstract Entities
You can specify that an entity is abstract—that is, that you will not create any instances of that entity. You typically make an entity abstract if you have a number of entities that all represent specializations of (inherit from) a common entity which should not itself be instantiated 


Properties
An entity's properties are its attributes and relationships, including its fetched properties (if it has any). 

A property name cannot be the same as any no-parameter method name of NSObject or NSManagedObject—for example, you cannot give a property the name “description” (see NSPropertyDescription). 


Attributes
Core Data natively supports a variety of attribute types, such as string, date, and integer (represented as instances of NSString, NSDate, and NSNumber respectively).

You can specify that an attribute is optional—that is, it is not required to have a value. In general, however, you are discouraged from doing so—especially for numeric values (typically you can get better results using a mandatory attribute with a default value—in the model—of 0). The reason for this is that SQL has special comparison behavior for NULL that is unlike Objective-C's nil. NULL in a database is not the same as 0, and searches for 0 will not match columns with NULL. 


Relationships
Core Data supports to-one and to-many relationships, and fetched properties. Fetched properties represent weak, one-way relationships. I 



Fetch Request Templates
You use the NSFetchRequest class to describe fetch requests to retrieve objects from a persistent store. It is often the case that you want to execute the same request on multiple occasions, or execute requests that follow a given pattern but which contain variable elements (typically supplied by the user). For example, you might want to be able to retrieve all publications written by a certain author, perhaps after a date specified by the user at runtime.

You can predefine fetch requests and store them in a managed object model as named templates. This allows you to pre-define queries that you can retrieve as necessary from the model. Typically, you define fetch request templates using the Xcode data modeling tool (see Xcode Tools for Core Data ). The template may include variables, as shown in Figure 2.




Configurations 

A configuration has a name and an associated set of entities. 


You typically use configurations if you want to store different entities in different stores. A persistent store coordinator can only have one managed object model, so by default each store associated with a given coordinator must contain the same entities.




Using a Managed Object Model

Creating and Loading a Managed Object Model 


Managed Object Model means abc.xcdatamodeld

Compiling a Data Model 
The model file is compiled using the model compiler, momc, to remove the extraneous information and make runtime loading of the resource as efficient as possible. An xcdatamodeld “source” directory is compiled into a momd deployment directory, and an xcdatamodel “source” file is compiled into a mom deployment file.
momc is located in /Developer/usr/bin/. If you want to use it in your own build scripts, its usage is momc source destination, where source is the path of the Core Data model to compile and destination is the path of the output. 


Loading a Data Model 

If you want to load a model yourself, there are two mechanisms you can use:

1.You can load a single model from a specific URL, using the instance method initWithContentsOfURL:. 
2. You can create a merged model from a specific collection of bundles, using the class method mergedModelFromBundles:.
 


Problems May Arise if Your Project Contains More Than One Model

If you simply rename your model file, Core Data attempts to merge the current and the old versions and you get an error similar to the following: 


reason = "'Can't merge models with two different entities named
'EntityName''";


If you create a new model that contains different entities from those in your original model, then Core Data merges the old and new models. If you have an existing store, you get an error similar to the following when you attempt to open it: 


reason = "The model used to open the store is incompatible with the one
used to create the store";


There are two solutions:

1. Make sure that you clean any old build products before running the application. If the application bundle itself contains old model files, you can delete the application. 

2. Instead of mergedModelFromBundles:, use initWithContentsOfURL: to initialize the model. The URL uniquely identifies a model so that Core Data will not merge the current model with any legacy models.
 



Changing the Schema Makes a Model Incompatible With Old Stores


If you add a new entity or a new attribute to an existing entity, you will not be able to open old stores; if you add a validation constraint or set a new default value for an attribute, you will be able to open old stores. 


Important: Ifyouwanttochangethemodelbutalsoretaintheabilitytoopenstorescreatedusinga previous version of the model, you must keep the previous version of the model (as a version in a versioned model). Core Data cannot open a store for which it has no compatible model. Thus, if you want to change the model but also retain the ability to open existing stores, you must:
  1. Ensure that you have a versioned model—if you don’t, make the current model into a versioned model.
  2. Before editing the schema , create a new version of the current model.
  3. Edit the new current version of the model, leaving the old version unaltered. 


Accessing and Using a Managed Object Model at Runtime 

Thus to get the model from a managed object context, you use the following code:
[[<#A managed object context#> persistentStoreCoordinator] managedObjectModel]; 


You can also retrieve the model from an entity description, so given a managed object you can retrieve its entity description and hence the model, as shown in the following example.
[[<#A managed object#> entity] managedObjectModel];


Creating Fetch Request Templates Programmatically


NSManagedObjectModel *model = <#Get a model#>;
NSFetchRequest *requestTemplate = [[NSFetchRequest alloc] init];
NSEntityDescription *publicationEntity =
    [[model entitiesByName] objectForKey:@"Publication"];
[requestTemplate setEntity:publicationEntity];
NSPredicate *predicateTemplate = [NSPredicate predicateWithFormat:
    @"(mainAuthor.firstName like[cd] $FIRST_NAME) AND \
        (mainAuthor.lastName like[cd] $LAST_NAME) AND \
        (publicationDate > $DATE)"];
[requestTemplate setPredicate:predicateTemplate];
[model setFetchRequestTemplate:requestTemplate
    forName:@"PublicationsForAuthorSinceDate"];



Accessing Fetch Request Templates
NSManagedObjectModel *model = <#Get a model#>;
NSError *error = nil;
NSDictionary *substitutionDictionary = [NSDictionary dictionaryWithObjectsAndKeys:

    @"Fiona", @"FIRST_NAME", @"Verde", @"LAST_NAME",
    [NSDate dateWithTimeIntervalSinceNow:-31356000], @"DATE", nil];
NSFetchRequest *fetchRequest =
    [model fetchRequestFromTemplateWithName:@"PublicationsForAuthorSinceDate"
            substitutionVariables:substitutionDictionary];
NSArray *results = 
    [aManagedObjectContext executeFetchRequest:fetchRequest error:&error]; 



Localizing a Managed Object Model
You localize a model by providing a localization dictionary that follows the pattern shown in the table below.

Key
Value
Note
"Entity/NonLocalizedEntityName"
"LocalizedEntityName"
"Property/NonLocalizedPropertyName/Entity/EntityName"
"LocalizedPropertyName"
1
"Property/NonLocalizedPropertyName"
"LocalizedPropertyName"


You can access the localization dictionary using the method localizationDictionary



Strings File
The easiest way to localize a model is to create a corresponding strings file—the strings file name is the same as the model file name, but with a .strings rather than a .xcdatamodel extension

"Entity/Emp" = "Employee";
"Property/firstName" = "First Name";
"Property/lastName" = "Last Name"; 
"Property/salary" = "Salary";

Setting a Localization Dictionary Programmatically
You can set a localization dictionary at runtime using the NSManagedObjectModel method setLocalizationDictionary: 

NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] init];
NSEntityDescription *runEntity = [[NSEntityDescription alloc] init];
[runEntity setName:@"Run"];
[runEntity setManagedObjectClassName:@"Run"];
[mom setEntities:@[runEntity]];
NSMutableArray *runProperties = [NSMutableArray array];
NSAttributeDescription *dateAttribute = [[NSAttributeDescription alloc] init];
[runProperties addObject:dateAttribute];
[dateAttribute setName:@"date"];
[dateAttribute setAttributeType:NSDateAttributeType];
[dateAttribute setOptional:NO];
NSAttributeDescription *idAttribute= [[NSAttributeDescription alloc] init];
[runProperties addObject:idAttribute];
[idAttribute setName:@"processID"];
[idAttribute setAttributeType:NSInteger32AttributeType];
[idAttribute setOptional:NO];
[idAttribute setDefaultValue:@0];
NSPredicate *validationPredicate = [NSPredicate predicateWithFormat:@"SELF >= 0"]; NSString *validationWarning = @"Process ID < 0";
[idAttribute setValidationPredicates:@[validationPredicate]

    withValidationWarnings:@[validationWarning]];
[runEntity setProperties:runProperties];
NSDictionary *localizationDictionary = @{
    @"Property/processID/Entity/Run" : @"Process ID",
    @"Property/date/Entity/Run" : @"Date"
    @"ErrorString/Process ID < 0" : @"Process ID must not be less than 0" };
[mom setLocalizationDictionary:localizationDictionary];

No comments:

Post a Comment