Используя персистентные хранилища

Эта статья описывает, как Вы создаете персистентное хранилище, и как можно переместить хранилище от одного типа до другого, и управлять метаданными хранилища. Для больше о персистентных типах хранилища, различия между ними, и как можно сконфигурировать аспекты их поведения, видят Персистентные Функции Хранилища.

Создание и доступ к хранилищу

Доступ к хранилищам установлен экземпляром NSPersistentStoreCoordinator. Вы не должны должны быть непосредственно получать доступ к файлу, содержащему хранилище. От персистентного координатора хранилища можно получить объект, представляющий определенное хранилище на диске. Базовые Данные обеспечивают NSPersistentStore класс для представления персистентных хранилищ.

Для создания хранилища Вы используете персистентного координатора хранилища. Необходимо указать тип хранилища, которое будет создаваться, дополнительно конфигурация модели управляемого объекта, связанной с координатором и ее расположением, если это не хранилище в памяти. Следующий фрагмент кода иллюстрирует, как можно создать хранилище XML только для чтения:

NSManagedObjectContext *moc = <#Get a context#>;
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];

Для получения хранилища возражают от координатора, Вы используете метод persistentStoreForURL:. Можно использовать хранилище для ограничения запроса выборки определенным хранилищем, как показано в следующем фрагменте кода:

NSPersistentStoreCoordinator *psc = <#Get a coordinator#>;
NSURL *myURL = <#A URL identifying a store#>;
NSPersistentStore *myStore = [psc persistentStoreForURL:myURL];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setAffectedStores:[NSArray arrayWithObject:myStore]];

Изменение типа и расположения хранилища

Можно переместить хранилище от одного типа или расположения другому (например, для операции Save As) использование NSPersistentStoreCoordinator метод migratePersistentStore:toURL:options:withType:error:. После вызова этого метода исходное хранилище удалено от координатора, таким образом хранилище не является поэтому больше полезной ссылкой. Метод проиллюстрирован в следующем фрагменте кода, показывающем, как можно переместить хранилище от одного расположения до другого. Если старый тип хранилища является XML, то пример также преобразовывает хранилище в SQLite

NSPersistentStoreCoordinator *psc = [aManagedObjectContext persistentStoreCoordinator];
NSURL *oldURL = <#URL identifying the location of the current store#>;
NSURL *newURL = <#URL identifying the location of the new store#>;
NSError *error = nil;
NSPersistentStore *xmlStore = [psc persistentStoreForURL:oldURL];
NSPersistentStore *sqLiteStore = [psc migratePersistentStore:xmlStore
    toURL:newURL
    options:nil
    withType:NSSQLiteStoreType
    error:&error];

Базовые Данные выполняют процедуру ниже для миграции хранилища:

  1. Создайте временный штабель персистентности

  2. Смонтируйте старые и новые хранилища

  3. Загрузите все объекты из старого хранилища

  4. Переместите объекты на новое хранилище

    Объектам дают временный IDs, затем присвоились к новому хранилищу. Новое хранилище тогда сохраняет недавно назначенные объекты (передающий их внешнему репозиторию).

    Базовые Данные тогда сообщают другим штабелям, что идентификаторы объектов изменились (от старого до новых хранилищ), который является, как вещи «продолжают работать» за миграцией.

  5. Размонтируйте старое хранилище

  6. Возвратите новое хранилище

Ошибка может произойти если:

В последних двух случаях Вы получаете те же ошибки, Вы были бы, если Вы вызвали addPersistentStore: или removePersistentStore: непосредственно. если ошибка происходит при добавлении или удалении хранилища, необходимо обработать это как исключение, так как штабель персистентности, вероятно, будет в противоречивом состоянии.

Если что-то перестало работать во время самой миграции, вместо ошибки Вы получаете исключение. В этих случаях Базовые Данные раскручиваются чисто и не должно быть никаких необходимых ремонтных работ. Можно исследовать описание исключения для определения то, что пошло не так, как надо — существует большое разнообразие возможных ошибок, в пределах от «диска полные» и «проблемы полномочий» к «Хранилищу SQLite, стал поврежденными» и «Базовыми Данными, не поддерживает перекрестные отношения хранилища».

Объединенные метаданные с хранилищем для предоставления индексации центра внимания дополнительной информации и поддержки

Метаданные хранилища предоставляют дополнительную информацию о хранилище, непосредственно не связанном ни с одним из объектов в хранилище.

Метаданные представлены словарем. Базовые Данные автоматически устанавливают пары ключ/значение для указания типа хранилища и его UUID. Можно добавить дополнительные ключи, которые могут быть или пользовательскими для приложения или одного из стандартного набора ключей для поддержки индексации Центра внимания (если Вы также пишете подходящее средство импорта), такой как kMDItemKeywords.

Необходимо быть осторожными, о какой информации Вы помещаете в метаданные. Во-первых, Центр внимания налагает предел размеру метаданных. Во-вторых, тиражирование всего документа в метаданных, вероятно, не полезно. Отметьте, тем не менее, что возможно создать URL для идентификации определенного объекта в хранилище (использование URIRepresentation) — URL может быть полезным для включения как метаданные.

Получение метаданных

Существует два способа получить метаданные для хранилища:

  1. Приведенный пример персистентного хранилища, можно получить его метаданные с помощью NSPersistentStoreCoordinator метод экземпляра metadataForPersistentStore:.

  2. Можно получить метаданные от хранилища без издержек создания штабеля персистентности с помощью NSPersistentStoreCoordinator метод класса, metadataForPersistentStoreOfType:URL:error:.

Между этими подходами существует важное различие. Метод экземпляра, metadataForPersistentStore:, возвращает метаданные, как это в настоящее время находится в Вашей программе, включая любые изменения, которые, возможно, были внесены, так как хранилище было в последний раз сохранено. Метод класса, metadataForPersistentStoreOfType:URL:error:, возвращает метаданные, поскольку они в настоящее время представляются в самом хранилище. Если там ожидают изменения в хранилище, возвращенное значение может поэтому быть вне синхронизации.

Установка метаданных

Существует два способа, которыми можно установить метаданные для хранилища:

  1. Приведенный пример персистентного хранилища, можно установить его метаданные с помощью NSPersistentStoreCoordinator метод экземпляра, setMetadata:forPersistentStore:.

  2. Можно установить метаданные без издержек создания штабеля персистентности с помощью NSPersistentStoreCoordinator метод класса, setMetadata:forPersistentStoreOfType:URL:error:.

Между этими подходами существует снова важное различие. Если Вы используете setMetadata:forPersistentStore:, необходимо сохранить хранилище (через контекст управляемого объекта), прежде чем будут сохранены новые метаданные. Если Вы используете setMetadata:forPersistentStoreOfType:URL:error:, однако, метаданные сразу обновляются (и измененная в последний раз дата измененного файла). Если Вы используете, это различие имеет определенные импликации NSPersistentDocument на OS X. Если Вы обновляете использование метаданных setMetadata:forPersistentStoreOfType:URL:error: в то время как Вы активно работаете над персистентным хранилищем (т.е. в то время как там не сохраняются изменения), тогда когда Вы сохраните документ, Вы будете видеть предупреждение, “Файл этого документа был изменен другим приложением, так как Вы открыли или сохранили его”. Для предотвращения этого необходимо вместо этого использовать setMetadata:forPersistentStore:. Для нахождения персистентного хранилища документа Вы обычно просите у персистентного координатора хранилища его персистентные хранилища (persistentStores) и используйте первый элемент в возвращенном массиве.

Поскольку Базовые Данные управляют значениями для NSStoreType и NSStoreUUID, необходимо сделать непостоянную копию любых существующих метаданных прежде, чем установить собственные ключи и значения, как проиллюстрировано в следующем фрагменте кода.

NSError *error;
NSURL *storeURL = <#URL identifying the location of the store#>;
 
NSDictionary *metadata =
    [NSPersistentStoreCoordinator metadataForPersistentStoreWithURL:storeURL error:&error]
if (metadata == nil) {
    /* Deal with the error. */
}
else {
    NSMutableDictionary *newMetadata = [metadata mutableCopy];
    newMetadata[(NSString *)kMDItemKeywords] = @[ @"MyKeyWord"] ];
    // Set additional key-value pairs as appropriate.
    [NSPersistentStore setMetadata:newMetadata
                       forPersistentStoreWithURL:storeURL
                       error:&error];
}