Thursday, July 18, 2013

Core Data Programming Guide Notes -- Part 2

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


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. 


A managed object is also associated with a managed object context (“context”). 


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.



Object Life-Cycle—Initialization and Deallocation
Core Data “owns” the life-cycle of managed objects 

The two other methods, awakeFromInsert and awakeFromFetch, allow you to differentiate between two different situations:


1.awakeFromInsert is invoked only once in the lifetime of an object—when it is first created. 

2. awakeFromFetch is invoked when an object is re-initialized from a persistent store (during a fetch).
Validation
 validateValue:forKey:error:




Managed Object Accessor Methods

You do need to write custom accessor methods if you use transient properties to support non-standard data types (see “Non-Standard Persistent Attributes” (page 91)) or if you use scalar instance variables to represent an attribute.


Custom implementation 
NSManagedObject disables automatic key-value observing (KVO) change notifications for modeled properties, and the primitive accessor methods do not invoke the access and change notification methods.


Important: You are strongly encouraged to use dynamic properties (that is, properties whose implementation you specify as @dynamic) instead of creating custom implementations for standard or primitive accessor methods. 




Creating and Deleting Managed Objects 


Creating, Initializing, and Saving a Managed Object 


  in three main ways—a managed object: 


  Must be an instance of NSManagedObject or of a class that inherits from NSManagedObject 

  Exists in an environment defined by its managed object context

  Has an associated entity description that describes the properties of the object 


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 Managed Object Context
The Entity Description
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
NSManagedObject *newEmployee = [[NSManagedObject alloc]
              initWithEntity:employeeEntity insertIntoManagedObjectContext:context];
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.
You specify the store for an object using the NSManagedObjectContext method, assignObject:toPersistentStore:.
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
[aContext deleteObject:aManagedObject];
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.
Fetching Managed Objects
Fetching Managed Objects
NSManagedObjectContext *moc = [self managedObjectContext];
  NSEntityDescription *entityDescription = [NSEntityDescription
      entityForName:@"Employee" inManagedObjectContext:moc];
  NSFetchRequest *request = [[NSFetchRequest alloc] init];
  [request setEntity:entityDescription];
  // Set example predicate and sort orderings...
  NSNumber *minimumSalary = ...;
  NSPredicate *predicate = [NSPredicate predicateWithFormat:
      @"(lastName LIKE[c] 'Worsley') AND (salary > %@)", minimumSalary];
  [request setPredicate:predicate];
  NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
      initWithKey:@"firstName" ascending:YES];
  [request setSortDescriptors:@[sortDescriptor]];
  NSError *error;
  NSArray *array = [moc executeFetchRequest:request error:&error];
  if (array == nil)
  {    
      // Deal with error...
  }
The count of the array returned from the fetch will be 0 if the target object has been deleted. If you need to test for the existence of several objects, it is more efficient to use the IN operator than it is to execute multiple fetches for individual objects, for example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self IN %@",
                                            arrayOfManagedObjectIDs];
Fetching Specific Values
Sometimes you don’t want to fetch actual managed objects; instead, you just want to retrieve—for example—the largest or smallest value of a particular attribute. In OS X v10.6 and later and on iOS, you can use NSExpressionDescription to directly retrieve values that meet your criteria.
You create a fetch request object and set its entity, just as you would for a normal fetch, but:
You specify that the fetch should return dictionaries.
You send the fetch request a setResultType: message with the argument NSDictionaryResultType.
You create instances of NSExpressionDescription to specify the properties you want to retrieve.
If you just want a single value—such as the largest salary in an Employee table—then you just create a single expression description.
There are a number of steps to follow to create and use the expression description.
First you need to create expressions (instances of NSExpression) to represent the key-path for the valueyou’re interested in, and to represent the function you want to apply (such as max: or min:):
NSExpression *keyPathExpression = [NSExpression
     expressionForKeyPath:@"salary"];
 NSExpression *maxSalaryExpression = [NSExpression
     expressionForFunction:@"max: arguments:[NSArray   
     arrayWithObject:keyPathExpression]];     
     
You then create the expression description and set its name, expression, and result type.
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
[expressionDescription setName:@"maxSalary"];
[expressionDescription setExpression:maxSalaryExpression];
[expressionDescription setExpressionResultType:NSDecimalAttributeType];
Finally, you set the request’s properties to fetch just the property represented by the expression:
[request setPropertiesToFetch:[NSArray
arrayWithObject:expressionDescription]];
Using Managed Objects
Accessing and Modifying Properties
NSString *firstName = [anEmployee firstName];
Employee *manager = anEmployee.manager;
newEmployee.firstName = @"Stig";
[newEmployee setManager:manager];
You can also use key-value coding (KVC) to get or set the value of a simple attribute as illustrated in the following code fragment.
[newEmployee setValue:@"Stig" forKey:@"firstName"];      
[aDepartment setValue:[NSNumber numberWithInteger:100000]
forKeyPath:@"manager.salary"];
You must, however, change attribute values in a KVC-compliant fashion. For example, the following typically represents a programming error:
NSMutableString *mutableString = [NSMutableString stringWithString:@"Stig"];
[newEmployee setFirstName:mutableString];
[mutableString setString:@"Laura"];
To-many relationships
NSMutableSet *employees = [aDepartment mutableSetValueForKey:@"employees"];
[employees addObject:newEmployee];
[employees removeObject:firedEmployee];
// or
[aDepartment addEmployeesObject:newEmployee];
[aDepartment removeEmployeesObject:firedEmployee];
[aDepartment.employees addObject:newEmployee]; // do not do this!   
then KVO change notifications are not emitted and the inverse relationship is not updated correctly.
Saving Changes

You can create and register managed 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.

Managed Object IDs and URIs
An NSManagedObjectID object is a universal identifier for a managed object, and provides basis for uniquing in the Core Data Framework. A managed object ID uniquely identifies the same managed object both between managed object contexts in a single application, and in multiple applications (as in distributed systems).

NSManagedObjectID *moID = [managedObject objectID];
There are two forms of an object ID. When a managed object is first created, Core Data assigns it a temporary ID; only if it is saved to a persistent store does Core Data assign a managed object a permanent ID. You can readily discover whether an ID is temporary:
BOOL isTemporary = [[managedObject objectID] isTemporaryID];
You can also transform an object ID into a URI representation:
NSURL *moURI = [[managedObject objectID] URIRepresentation];

Undo Management
The Core Data framework provides automatic support for undo and redo. Undo management even extends to transient properties (properties that are not saved to persistent store, but are specified in the managed object model).
Managed objects are associated with a managed object context. Each managed object context maintains an undo manager. The context uses key-value observing to keep track of modifications to its registered objects.
To undo an operation, you simply send the context an undo message and to redo it send the context a redo message. You can also roll back all changes made since the last save operation using rollback (this also clears the undo stack) and reset a context to its base state using reset.
NSManagedObjectContext *moc = ...;
[moc processPendingChanges];  // flush operations for which you want undos
[[moc undoManager] disableUndoRegistration];
// make changes for which undo operations are not to be recorded
[moc processPendingChanges];  // flush operations for which you do not want undos
[[moc undoManager] enableUndoRegistration];
Faults
NSString *managersName =[[anEmployee valueForKey:@"manager"] valueForKey:@"lastName];
or more easily using key paths:
NSString *managersName = [anEmployee valueForKeyPath:@"manager.lastName"];
Ensuring Data Is Up-to-Date
To refresh a managed object's property values, you use the managed object context method refreshObject:mergeChanges:. If the mergeChanges flag is YES, the method merges the object's property values with those of the object available in the persistent store coordinator; if the flag is NO, the method simply turns an object back into a fault without merging (which also causes strong references to other related managed objects to be broken, so you can use this method to trim the portion of your object graph you want to hold in memory).

No comments:

Post a Comment