Thursday, July 18, 2013

Core Data Programming Guide Notes -- Part 3

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



Object Lifetime Management 

The Role of the Managed Object Context 

his means that in general you cannot rely on a context to ensure the longevity of a managed object instance, and you cannot rely on the existence of a managed object to ensure the longevity of a context.


The exception to this rule is that a managed object context maintains a strong reference to any changed (inserted, deleted, and updated) objects until the pending transaction is committed (with a save:) or discarded (with a reset or rollback). 

 If you have finished with a managed object context, or for some other reason you want to “disconnect” a context from its persistent store coordinator, you should not set the context’s coordinator to nil:

// This will raise an exception
[myManagedObjectContext setPersistentStoreCoordinator:nil];


Instead, you should simply relinquish ownership of the context and allow it to be deallocated normally. 


Breaking Relationship Strong Reference Cycles

To ensure that reference cycles are broken, when you're finished with an object you can use the managed object context method refreshObject:mergeChanges: to turn it into a fault.

Change and Undo Management

A context keeps strong references to managed objects that have pending changes (insertions, deletions, or updates) until the context is sent a save:, reset , rollback, or dealloc message, or the appropriate number of undos to undo the change. 

The undo manager associated with a context keeps strong references to any changed managed objects.




Relationships and Fetched Properties

Core Data does not let you create relationships that cross stores. If you need to create a relationship from objects in one store to objects in another, you should consider using fetched properties.


Relationship Fundamentals

A relationship specifies the entity, or the parent entity, of the objects at the destination. This can be the same as the entity at the source (a reflexive relationship).

You can specify a relationship as being to-one or to-many. To-one relationships are represented by a reference to the destination object. To-many relationships are represented by mutable sets (although fetched properties are represented by arrays). Implicitly, “to-one” and “to-many” typically refer to “one-to-one” and “one-to-many” relationships respectively. A many-to-many relationship is one where a relationship and its inverse are both to-many.


You can also put upper and lower limits on the number of objects at the destination of a to-many relationship. The lower limit does not have to be zero. You can if you want specify that the number of employees in a department must lie between 3 and 40. You also specify a relationship as either optional or not optional. If a relationship is not optional, then in order to be valid there must be an object or objects at the destination of the relationship.

Relationship Delete Rules
A relationship's delete rule specifies what should happen if an attempt is made to delete the source object.


Deny
If there is at least one object at the relationship destination, then the source object cannot be deleted.
For example, if you want to remove a department, you must ensure that all the employees in that department are first transferred elsewhere (or fired!) otherwise the department cannot be deleted.


Nullify
Set the inverse relationship for objects at the destination to null.
For example, if you delete a department, set the department for all the current members to null. This only makes sense if the department relationship for an employee is optional, or if you ensure that you set a new department for each of the employees before the next save operation.


Cascade
Delete the objects at the destination of the relationship.
For example, if you delete a department, fire all the employees in that department at the same time.


No Action
Do nothing to the object at the destination of the relationship.
For example, if you delete a department, leave all the employees as they are, even if they still believe they belong to that department.

Manipulating Relationships and Object Graph Integrity

anEmployee.department = newDepartment;
Alternatively, you can use:
[newDepartment addEmployeeObject:anEmployee];

Many-to-Many Relationships 
  
You must define many-to-many relationships in both directions—that is,you must specify two relationships, each being the inverse of the other. You can’t just define a to-many relationship in one direction and try to use it as a many-to-many. If you do, you will end up with referential integrity problems.



Unidirectional Relationships

in general, you should avoid using unidirectional relationships. Bidirectional relationships provide the framework with additional information with which to better maintain the object graph. If you do want to use unidirectional relationships, you need to do some of this maintenance yourself. In the case above, this would mean that after this line of code:

[managedObjectContext deleteObject:department]; 
 you should write:
[employee setValue:nil forKey:@"department"];


 Cross-Store Relationships
You must be careful not to create relationships from instances in one persistent store to instances in another persistent store, as this is not supported by Core Data. If you need to create a relationship between entities in different stores, you typically use fetched properties.


Fetched Properties
Fetched properties represent weak, one-way relationships. 
A fetched property is like a relationship, but it differs in several important ways:

  •  Rather than being a "direct" relationship, a fetched property's value is calculated using a fetch request. (The fetch request typically uses a predicate to constrain the result.) 
  • A fetched property is represented by an array, not a set. The fetch request associated with the property can have a sort ordering, and thus the fetched property may be ordered. 
  • A fetched property is evaluated lazily, and is subsequently cached.

You use refreshObject:mergeChanges: to manually refresh the properties—this causes the fetch request associated with this property to be executed again when the object fault is next fired. 
 There are two special variables you can use in the predicate of a fetched property—$FETCH_SOURCE and $FETCHED_PROPERTY.



Non-Standard Persistent Attributes 

he principle behind the two approaches is the same: you present to consumers of your entity an attribute of the type you want, and “behind the scenes” it’s converted into a type that Core Data can manage. 


Transformable Attributes



Managed Object Validation

There are two types of validation—property-level and inter-property. You use property-level validation to ensure the correctness of individual values; you use inter-property validation to ensure the correctness of combinations of values.

Core Data Validation
Cocoa provides a basic infrastructure for model value validation. It requires you, though, to write code for all the constraints you want to apply. Core Data allows you to put validation logic into the managed object model.

If you do want to customize validation of individual properties, you use standard validation methods as defined by the NSKeyValueCoding protocol 

Property-Level Validation 


The NSKeyValueCoding protocol specifies a method—validateValue:forKey:error:—that provides general support for validation methods in a similar way to that in which valueForKey: provides support for accessor methods. 


If you want to implement logic in addition to the constraints you provide in the managed object model, you should not override validateValue:forKey:error:. Instead you should implement methods of the form validate:error:


If you do implement custom validation methods, you should typically not invoke 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 also applied. 
-(BOOL)validateAge:(id*)ioValue error:(NSError **)outError{}


The input value is a pointer to object reference (an id *). This means that in principle you can change the input value 

Inter-Property validation
NSManagedObject provides additional loci for validation—update, insertion, and deletion—through the validateFor... methods such as validateForUpdate:. 



Combining Validation Errors



Faulting and Uniquing

Faulting is a mechanism Core Data employs to reduce your application’s memory usage. 
Faulting Limits the Size of the Object Graph

A fault is a placeholder object that represents a managed object that has not yet been fully realized, or a collection object that represents a relationship: 

1. A managed object fault is an instance of the appropriate class, but its persistent variables are not yet initialized.
2. A relationship fault is a subclass of the collection class that represents the relationship. 


To illustrate, consider an application that allows a user to fetch and edit details about a single employee. The employee has a relationship to a manager and to a department, and these objects in turn have other relationships. If you retrieve just a single Employee object from a persistent store, its manager, department, and reports relationships are initially represented by faults. Figure 1 shows an employee’s department relationship represented by a fault.




Fault handling is transparent—you do not have to execute a fetch to realize a fault.


If at some stage a persistent property of a fault object is accessed, then Core Data automatically retrieves the data for the object and initializes the object.

Firing Faults 


Turning Objects into Faults 

Turning a realized object into a fault can be useful in pruning the object graph.

Turning a managed object into a fault releases unnecessary memory, sets its in-memory property values to nil, and breaks strong references to related objects.

You can turn a realized object into a fault with the refreshObject:mergeChanges: method. If you pass NO as the mergeChanges argument, you must be sure that there are no changes to that object’s relationships.

When an object turns into a fault, it is sent a didTurnIntoFault message. You may implement a custom didTurnIntoFault method to perform various “housekeeping” function

Uniquing Ensures a Single Managed Object per Record per Context

Core Data ensures that—in a given managed object context—an entry in a persistent store is associated with only one managed object. The technique is known as uniquing.  


For example, consider the situation illustrated in Figure 2; two employees have been fetched into a single managed object context . Each has a relationship to a department, but the department is currently represented by a fault.



It would appear that each employee has a separate department, and if you asked each employee for their department in turn—turning the faults into regular objects—you would have two separate Department objects in memory. However, if both employees belong to the same department (for example, "Marketing"), then Core Data ensures that (in a given managed object context) only one object representing the Marketing department is ever created. If both employees belong to the same department, their department relationships would both therefore reference the same fault


 

No comments:

Post a Comment