< Previous PageNext Page > Hide TOC

Using Persistent Stores

This article describes how you create a persistent store, and how you can migrate a store from one type to another, and manage store metadata. For more about persistent store types, the differences between them, and how you can configure aspects of their behavior, see “Persistent Store Features.”

Contents:

Creating and Accessing a Store
Changing a Store's Type and Location
Store Metadata


Creating and Accessing a Store

Access to stores is mediated by an instance of NSPersistentStoreCoordinator. You should not need to directly access a file containing a store. From a persistent store coordinator, you can retrieve an object that represents a particular store on disk. On Mac OS X v10.5 and later, Core Data provides an NSPersistentStore class to represent persistent stores.

To create a store, you use a persistent store coordinator. You must specify the type of the store to be created, optionally a configuration of managed object model associated with the coordinator, and its location if it is not an in-memory store. The following code fragment illustrates how you can create a read-only XML store:

NSManagedObjectContext *moc = /* get a context from somewhere */ ;
NSPersistentStoreCoordinator *psc = [moc persistentStoreCoordinator];
NSError *error = nil;
NSDictionary *options =
    [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:1]
                    forKey:NSReadOnlyPersistentStoreOption];
 
NSPersistentStore *roStore =
    [psc addPersistentStoreWithType:NSXMLStoreType
                    configuration:nil URL:url
                    options:options error:&error];

To retrieve a store object from a coordinator, you use the method persistentStoreForURL:. You can use a store to restrict a fetch request to a specific store, as shown in the following code fragment:

NSPersistentStoreCoordinator *psc =  /* get a coordinator from somewhere */ ;
NSURL *myURL = ...; // assume this exists
NSPersistentStore *myStore = [psc persistentStoreForURL:myURL];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setAffectedStores:[NSArray arrayWithObject:myStore]];

Changing a Store's Type and Location

You can migrate a store from one type or location to another (for example, for a Save As operation) using the NSPersistentStoreCoordinator method migratePersistentStore:toURL:options:withType:error:. After invocation of this method, the original store is removed from the coordinator, thus store is therefore no longer a useful reference. The method is illustrated in the following code fragment, which shows how you can migrate a store from one location to another. If the old store type is XML, then the example also converts the store to SQLite

NSPersistentStoreCoordinator *psc = [aManagedObjectContext persistentStoreCoordinator];
NSURL *oldURL, *newURL; // define URLs...
NSError *error = nil;
NSPersistentStore *xmlStore = [psc persistentStoreForURL:oldURL];
NSPersistentStore *sqLiteStore = [psc migratePersistentStore:xmlStore
    toURL:newURL
    options:nil
    withType:NSSQLiteStoreType
    error:&error];

Core Data follows the procedure below to migrate a store:

  1. Create a temporary persistence stack

  2. Mount the old and new stores

  3. Load all objects from the old store

  4. Migrate the objects to the new store

    The objects are given temporary IDs, then assigned to the new store. The new store then saves the newly assigned objects (committing them to the external repository).

    Core Data then informs other stacks that the object IDs have changed (from the old to the new stores), which is how things "keep running" after a migration.

  5. Unmount old store

  6. Return the new store

An error can occur if:

In the latter two cases, you get the same errors you would if you called addPersistentStore: or removePersistentStore: directly. if an error occurs when adding or removing the store, you should treat this as an exception since the persistence stack is likely to be in an inconsistent state.

If something fails during the migration itself, instead of an error you get an exception. In these cases, Core Data unwinds cleanly and there should be no repair work necessary. You can examine the exception description to determine what went wrong—there is a wide variety of possible errors, ranging from "disk is full" and "permissions problems" to "The SQLite store became corrupted" and "Core Data does not support cross store relationships".

Store Metadata

You can associate metadata with a store so that (if you write a suitable importer) it can be efficiently indexed by Spotlight. NSPersistentStoreCoordinator provides a class method, metadataForPersistentStoreWithURL:error:, that allows you to retrieve metadata from a store without the overhead of creating a persistence stack. On Mac OS X v10.5 and later, you can also use the NSPersistentStore method metadataForPersistentStoreWithURL:error:.

On Mac OS X v10.5 and later, you set the metadata for a store using the NSPersistentStore method setMetadata:forPersistentStoreWithURL:error:.

The metadata is a dictionary of key-value pairs, where a key may be either custom for your application, or one of the standard set of Spotlight keys such as kMDItemKeywords. Core Data automatically sets values for NSStoreType and NSStoreUUID, so you should make a mutable copy of the existing metadata then add your own keys and values, as illustrated in the following code fragment.

NSError *error = nil;
NSURL *storeURL = /* URL for persistent store */ ;
 
NSDictionary *metadata =
    [NSPersistentStore metadataForPersistentStoreWithURL:storeURL error:&error]
if (metadata == nil)
{
    /* deal with the error */
}
else
{
    NSMutableDictionary *newMetadata =
            [[metadata mutableCopy] autorelease];
    [newMetadata setObject:[NSArray arrayWithObject:@"MyKeyWord"]
            forKey:(NSString *)kMDItemKeywords];
    // set additional key-value pairs as appropriate
    [NSPersistentStore setMetadata:newMetadata
                       forPersistentStoreWithURL:storeURL
                       error:&error];
}

Mac OS X v10.4: On Mac OS X v10.4, you set the metadata for a store using NSPersistentStoreCoordinator's setMetadata:forPersistentStore: method. This takes as its second argument a store identifier. You retrieve a store identifier from the persistent store coordinator, using the URL as an identifier, as illustrated in the following code fragment.

NSURL *url = /* the URL for a store */ ;
NSManagedObjectContext *managedObjectContext =
        /* get a managed object context from somewhere */ ;
NSPersistentStoreCoordinator *psc =
        [managedObjectContext persistentStoreCoordinator];
id pStore = [psc persistentStoreForURL:url];
If pStore is not nil, you can set the metadata.

if (pStore != nil) {
    NSMutableDictionary *metadata =
            [[[psc metadataForPersistentStore:pStore] mutableCopy] autorelease];
    [metadata setObject:[NSArray arrayWithObject:@"MyKeyWord"]
            forKey:(NSString *)kMDItemKeywords];
    // set additional key-value pairs
    [psc setMetadata:metadata forPersistentStore:pStore];
}

Note that setting the metadata for a store does not change the information on disk until the store is actually saved.

You should be careful about what information you put into metadata. First, Spotlight imposes a limit to the size of metadata. Second, replicating an entire document in metadata is probably not useful. Note, though, that is is possible to create a URL to identify a particular object in a store (using URIRepresentation)—the URL may be useful to include as metadata.

An example of setting metadata and writing an importer is given in NSPersistentDocument Core Data Tutorial.



< Previous PageNext Page > Hide TOC


© 2004, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-03-04)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.