Atomic Store Life-cycle
This article describes the life-cycle of an atomic store. You should read this article to learn what methods are invoked on a store when, and what the store is expected to do as a result. This will help you to understand how to implement a custom store.
Registration
To use a custom store type in an application, you must register the store type with the NSPersistentStoreCoordinator
class using registerStoreClass:forStoreType:
. For more details, see Registering a Custom Store Type.
Initialization and Loading Data
You create an instance of store of a given type using the NSPersistentStoreCoordinator
method addPersistentStoreWithType:configuration:URL:options:error:
. You must implement the appropriate methods to properly initialize your store and load its contents.
Initializing the Store
The coordinator allocates a new store and initializes it using with initWithPersistentStoreCoordinator:configurationName:URL:options:
. This method is invoked both for new stores and for existing stores; your implementation of initWithPersistentStoreCoordinator:configurationName:URL:options:
should therefore check whether a file exists at the given URL—if it does not, you must create it.
You must also initialize the metadata for the store. After initWithPersistentStoreCoordinator:configurationName:URL:options:
, the coordinator invokes metadata
on the new store; at this point the metadata must be correct.
After the store is initialized, coordinator instructs the store to load its data by sending it a load:
message.
Loading a File
The load:
method should retrieve the store’s data from the URL specified for the store in initWithPersistentStoreCoordinator:configurationName:URL:options:
. The load:
method should parse the contents of the store to extract the persistent data and create a reference data object—such as a dictionary—for each element.
For each object to be represented, your store must do the following:
Create a managed object ID with the reference data and entity type for the node, using
objectIDForEntity:referenceObject:
.The object ID for a cache node is also the object ID for a managed object representing the cache node.
Create a cache node (an instance of
NSAtomicStoreCacheNode
), usinginitWithObjectID:
.The store must provide a mutable property cache object for each node.
(Optional) Push the corresponding persisted data into the node.
This step may be omitted if you implement lazy loading or other behavior.
The default implementation of
NSAtomicStoreCacheNode
provides key-value coding compliant access for property storage, so for the common case you do not need to create a custom subclass ofNSAtomicStoreCacheNode
.
Once all of the nodes have been created, you register them with the store using addCacheNodes:
.
At this point, the cache now has registered nodes and the framework is ready. Core Data will handle all requests for fetches, and create managed objects from the underlying cache node information.
This process is described in greater detail, with examples, in Initialization and Loading Data.
Zero-Length Files
Any subclass of NSAtomicStore
must be able to handle being initialized with a URL pointing to a zero-length file. This serves as an indicator that a new store is to be constructed at the specified location and allows you to securely create reservation files in known locations which can then be passed to Core Data to construct stores.
You may choose to create zero-length reservation files during an initWithPersistentStoreCoordinator:configurationName:URL:options:
or load:
method. If you do so, you must remove the reservation file if the store is removed from the coordinator before it is saved.
Processing and Saving Changes
When a managed object context is sent a save:
message, any associated store must (in this order) process all of the inserted, updated, and deleted objects that are assigned to it (the store), and then commit any changes to the external repository.
New objects
For each newly-inserted object in the context, the store receives a
newReferenceObjectForManagedObject:
message. Your store must provide a unique—and unchanging—value for this instance and entity type for the store (see New Reference Objects).After the reference data is returned, the store requests a new cache node be created for each of these objects using
newCacheNodeForManagedObject:
.NSAtomicStore
provides a default implementation that should suffice in most cases, However, if you wish to customize the creation of the cache nodes or use custom cache nodes, you can overridenewCacheNodeForManagedObject:
. In your implementation, you should create the cache node with the managed object ID from included managed object, and the values to be persisted should be pushed from the managed object into the cache node. You then register the new nodes with the store, usingaddCacheNodes:
Updated objects
For all objects which are changed in the context, the store receives a
updateCacheNode:fromManagedObject:
message. The arguments for the method are the cache node and managed object pair (which share the same object ID.) The store must push the persisted values from the managed object into the cache node.Deleted objects
Your store receives a
willRemoveCacheNodes:
callback; if necessary you can override this method to break any strong reference cycles to ensure that deleted objects are reclaimed.Saving changes
Finally, the store receives a
save:
message to commit the changes to the external repository.Your store must write the data (the cache nodes) and the metadata to the URL specified for the store in whatever format it uses.
New Reference Objects
Your implementation of newReferenceObjectForManagedObject:
must return a stable (unchanging) value for any given object. If you don’t do this, then Save As and migration operations will not work correctly.
This means that you can only use arbitrary numbers, UUIDs, or other random values if you save the value together with the rest of the data for a given object. If you cannot save the originally-assigned reference object, then newReferenceObjectForManagedObject:
must derive the reference object from the managed object's values. As this constraint exists for Save As and store migration operations, you could also use a side table or in-memory structure to ensure that a newly-migrated store loads its atomic store cache nodes with the same objectIDs that the current managed object context is using for the migrated managed objects.
Removal and Deallocation
If a store is to be removed from the coordinator, it receives the message willRemoveFromPersistentStoreCoordinator:
. In a custom atomic store class, you can override this method to implement clean-up or other behavior. If you do, your implementation of willRemoveFromPersistentStoreCoordinator:
should invoke super’s implementation.
Note that the coordinator parameter may be nil
if:
There was an error during the load: method, and the store cannot be added to the coordinator
The coordinator is in the process of being deallocated.
In these cases, willRemoveFromPersistentStoreCoordinator:
is invoked to allow you to perform any necessary resource cleanup (such as removal of reservation files—see Zero-Length Files).
Copyright © 2011 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2011-10-12