Implementing an Incremental Store
There are Several Methods you Must Implement
The designated initializer for an incremental store is initWithPersistentStoreCoordinator:configurationName:URL:options:. This method is expected to return a store object.
When you implement a custom incremental store, there are several methods that you must implement. In the order in which they are likely to be called, they are:
Metadata Loads After a Store Is Created
Once a store has been created, the persistent store coordinator invokes loadMetadata: on it. In your implementation, if all goes well you should typically load the store metadata, call setMetadata: to store the metadata, and return YES. If an error occurs, however (if the store is invalid for some reason—for example, if the store URL is invalid, or the user doesn’t have read permission for the store URL), create an NSError object that describes the problem, assign it to the error parameter passed into the method, and return NO.
In the specific case where the store is new, you may choose not to generate metadata in loadMetadata:, but instead allow it to be automatically generated. In this case, the call to setMetadata: is not necessary.
If the metadata is generated automatically, the store identifier will set to a generated UUID. To override this automatic UUID generation, override identifierForNewStoreAtURL: to return an appropriate value. Store identifiers should either be persisted as part of the store metadata, or uniquely derivable in some way such that a given store will have the same identifier even if added to multiple persistent store coordinators. The identifier may be any type of object, although if you want object IDs created by your store to respond to URIRepresentation or for managedObjectIDForURIRepresentation: to be able to parse the generated URI representation, it should be an instance of NSString.
Interaction with a Store is Mediated by Requests
The main method by which the Core Data stack interacts with an incremental store is executeRequest:withContext:error:. This method is called when the user does something which executes a fetch request, or the user saves a managed object context. See NSFetchRequest and NSSaveChangesRequest for information about these specific types of requests, including their configuration options and expected return values.
Your implementation of executeRequest:withContext:error: must take account of the different types of request.
If the request is a fetch request, you determine what objects are being requested based on the fetch entity, the value of
includesSubentities, and what type of data should be returned (seeNSIncrementalStore.hfor a more complete description of expected return values).If the expected result type is
NSManagedObjectResultType, you should useobjectWithID:to create an appropriate instance of the object; note that it is not necessary to populate the managed object with attribute or relationship values at this point (see Faulting below).If the request includes a predicate and/or sort descriptors, you use them to filter and/or order the results appropriately.
If the request is a save request, you record the changes provided in the request’s
insertedObjects,updatedObjects, anddeletedObjectscollections. Note there is also alockedObjectscollection; this collection contains objects which were marked as being tracked for optimistic locking (through thedetectConflictsForObject:: method); you may choose to respect this or not.In the case of a save request containing objects which are to be inserted,
executeRequest:withContext:error:is preceded by a call toobtainPermanentIDsForObjects:error:; Core Data will assign the results of this call as the objectIDs for the objects which are to be inserted. Once these IDs have been assigned, they cannot change. Note that if an empty save request is received by the store, this must be treated as an explicit request to save the metadata, but that store metadata should always be saved if it has been changed since the store was loaded.
You must support the following properties of NSFetchRequest: entity, predicate, sortDescriptors, fetchLimit, resultType, includesSubentities, returnsDistinctResults (in the case of NSDictionaryResultType), propertiesToFetch (in the case of NSDictionaryResultType), fetchOffset, fetchBatchSize, shouldRefreshRefetchedObjects, propertiesToGroupBy, and havingPredicate. If a store does not have underlying support for a feature (propertiesToGroupBy, havingPredicate), it should either emulate the feature in memory or return an error. Note that these are the properties that directly affect the contents of the array to be returned.
You may optionally ignore the following properties of NSFetchRequest: includesPropertyValues, returnsObjectsAsFaults, relationshipKeyPathsForPrefetching, and includesPendingChanges (this is handled by the managed object context). (These are properties that allow for optimization of I/O and do not affect the results array contents directly.)
Methods to Map Between Primary Keys and Object IDs
Two methods—newObjectIDForEntity:referenceObject: and referenceObjectForObjectID:—map between the primary key information used in the store and the object IDs used by Core Data.
Incremental Stores Support Faulting
Faulting (see “Faulting and Uniquing”) allows for increased flexibility in memory use by deferring the materialization of property values until they are needed by the user. NSIncrementalStore provides two methods to support faulting: newValuesForObjectWithID:withContext:error: and newValueForRelationship:forObjectWithID:withContext:error:. These methods allow for deferred loading of attribute and relationship data respectively.
When a managed object is first returned as part of the result set from executeRequest:withContext:error: it is a fault. At some later point, the user may attempt to access properties of that object, at which point Core Data will call newValuesForObjectWithID:withContext:error: and/or newValueForRelationship:forObjectWithID:withContext:error: for the object. See NSIncrementalStore.h and NSIncrementalStoreNode.h for more information about the what should be returned from these methods.
NSIncrementalStore provides two methods, managedObjectContextDidRegisterObjectsWithIDs: and managedObjectContextDidUnregisterObjectsWithIDs: that you use to track what managed objects are currently in use by the stack; this allows stores to flush data as it becomes unused. It is not necessary for stores to keep strong references to any data backing objects that are in use—you must balance the I/O cost of re-retrieving data with the cost of maintaining it in memory. The default implementations of these methods do nothing; they can be overridden by store implementers to allow their stores to maintain resources that are in use and dispose of resources that are no longer needed.
© 2011 Apple Inc. All Rights Reserved. (Last updated: 2011-10-12)