Используя модель управляемого объекта

Эта статья описывает, как Вы используете модель управляемого объекта в своем приложении.

Создание и загрузка модели управляемого объекта

Вы обычно создаете модель в XCode, как описано в Базовом редакторе Модели данных Хелпе. Можно также создать модель полностью в коде, как показывают в Перечислении 3 и описал в Базовом Учебном руководстве по Утилите Данных — обычно, однако, это слишком многоречиво для рассмотрения в чем-либо кроме самого тривиального приложения. (Вы, тем не менее, призваны рассмотреть учебное руководство для получения понимания того, что инструмент моделирования делает, и в частности получать оценку, что модель является просто набором объектов.)

Компиляция модели данных

Модель данных является ресурсом развертывания. В дополнение к подробным данным объектов и свойств в модели, модель, которую Вы создаете в XCode, содержит информацию о схеме — ее расположение, цвета элементов, и т.д. Во время выполнения не необходима эта последняя информация. Файл модели компилируется с помощью компилятора модели, momc, удалить постороннюю информацию и сделать загрузку во время выполнения ресурса максимально эффективной. xcdatamodeld «исходный» каталог компилируется в a momd каталог развертывания, и xcdatamodel «исходный» файл компилируется в a mom файл развертывания.

momc расположен в /Developer/usr/bin/. Если Вы хотите использовать его в своих собственных сценариях сборки, ее использование momc source destination, где источник является путем Базовой Модели данных для компиляции, и место назначения является путем вывода.

Загрузка модели данных

В некоторых случаях Вы не должны писать код для загрузки модели. Если Вы используете основанное на документе приложение на OS X, NSPersistentDocument управляет задачей нахождения и загрузки модели Вашего приложения для Вас. Если Вы используете XCode для создавания приложения недокумента, использующего Базовые Данные (для OS X или для iOS), делегат приложения включает код для получения модели. Во время выполнения имя модели — как представлено именем файла, используемым для хранения его на диске — не релевантно. Как только модель загружается Базовыми Данными, имя файла бессмысленно и имеет быть бесполезное, таким образом, можно назвать файл модели вообще, Вам нравится.

Если Вы хотите загрузить модель сами, существует два механизма, которые можно использовать:

  • Можно загрузить единственную модель из определенного URL, с помощью метода экземпляра initWithContentsOfURL:.

    Это - обычно предпочтенный метод. Обычно приложение имеет единственную модель, и использующий этот метод, Вы гарантируете, чтобы Вы загрузили только ту модель. Можно также загрузить отдельные модели через URLs и затем объединить их использование modelByMergingModels: прежде, чем инстанцировать координатора с ними.

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

  • Можно создать объединенную модель из определенного набора пакетов, с помощью метода класса mergedModelFromBundles:.

    Этот метод может быть полезным в случаях, где сегрегация моделей не важна — например, можно знать приложение и платформу, которую это соединяет с обоими, имеют модели, в которых Вы нуждаетесь или хотите загрузиться. Метод класса позволяет Вам легко загружать все модели сразу, не имея необходимость рассматривать то, что имена или вставляют специализированный код инициализации, чтобы гарантировать, что найдены все Ваши модели.

Если Ваш Проект Содержит больше чем Одну Модель, проблемы Могут Возникнуть

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

  • При простом переименовании файла модели Базовые Данные пытаются объединить ток и старые версии, и Вы получаете ошибку, подобную следующему:

    reason = "'Can't merge models with two different entities named 'EntityName''";
  • Если Вы создаете новую модель, содержащую различные объекты от тех в Вашей исходной модели, то Базовые Данные объединяют старые и новые модели. Если у Вас есть существующее хранилище, Вы получаете ошибку, подобную следующему, когда Вы пытаетесь открыть его:

    reason = "The model used to open the store is incompatible with the one used to create the store";

Существует два решения:

  • Удостоверьтесь, что Вы чистите любые старые продукты сборки прежде, чем запустить приложение. Если сам комплект приложений содержит старые файлы модели, можно удалить приложение.

  • Вместо mergedModelFromBundles:, использовать initWithContentsOfURL: инициализировать модель. URL однозначно определяет модель так, чтобы Базовые Данные не объединяли текущую модель ни с какими устаревшими моделями.

Изменение схемы делает модель несовместимой со старыми хранилищами

Поскольку модель описывает структуру данных в персистентном хранилище, изменяя любые части модели, изменяющейся, схема представляет его несовместимый с (и настолько неспособный открыться) хранилища, которые это ранее создало. При изменении схемы поэтому необходимо переместить данные в существующих хранилищах к новой версии (см. Базовое Руководство по программированию Управления версиями и Миграции данных Модели данных). Например, если Вы добавите новый объект или новый атрибут к существующему объекту, то Вы не будете в состоянии открыть старые хранилища; если Вы добавите ограничение проверки или установите новое значение по умолчанию для атрибута, то Вы будете в состоянии открыть старые хранилища.

Получая доступ и Используя модель управляемого объекта во время выполнения

Иногда необходимо получать доступ к модели во время выполнения, обычно к — например — получают шаблон запроса выборки, локализованное имя объекта, или возможно тип данных атрибута. Можно также хотеть программно изменить модель (можно сделать это только, прежде чем она будет использоваться во время выполнения, посмотрите NSManagedObjectModel). Существует много способов, которыми можно получить доступ к модели управляемого объекта во время выполнения. Через персистентность складывают Вас, в конечном счете получают модель от персистентного координатора хранилища. Таким образом для получения модели от контекста управляемого объекта Вы используете следующий код:

[[<#A managed object context#> persistentStoreCoordinator] managedObjectModel];

Можно также получить модель из описания объекта, так учитывая управляемый объект, можно получить его описание объекта и следовательно модель, как показано в следующем примере.

[[<#A managed object#> entity] managedObjectModel];

В некоторых случаях Вы поддерживаете «прямую» ссылку на модель — т.е. метод, возвращающий модель непосредственно. NSPersistentDocument обеспечивает managedObjectModel это возвращает модель, связанную с персистентным координатором хранилища, используемым контекстом управляемого объекта документа. Если Вы используете шаблон Core Data Application, делегат приложения поддерживает ссылку на модель.

Создание шаблонов запроса выборки программно

Можно создать шаблоны запроса выборки программно и связать их с использованием модели setFetchRequestTemplate:forName: как проиллюстрировано в Перечислении 1. Вспомните, тем не менее, что можно только изменить модель, прежде чем она использовалась координатором хранилища.

Перечисление 1  , Создающее выборку, запрашивает шаблон программно

NSManagedObjectModel *model = <#Get a model#>;
NSFetchRequest *requestTemplate = [[NSFetchRequest alloc] init];
NSEntityDescription *publicationEntity =
    [[model entitiesByName] objectForKey:@"Publication"];
[requestTemplate setEntity:publicationEntity];
 
NSPredicate *predicateTemplate = [NSPredicate predicateWithFormat:
    @"(mainAuthor.firstName like[cd] $FIRST_NAME) AND \
        (mainAuthor.lastName like[cd] $LAST_NAME) AND \
        (publicationDate > $DATE)"];
[requestTemplate setPredicate:predicateTemplate];
 
[model setFetchRequestTemplate:requestTemplate
    forName:@"PublicationsForAuthorSinceDate"];

Доступ к шаблонам запроса выборки

Можно получить и использовать шаблон запроса выборки, как проиллюстрировано во фрагменте кода в Доступе и Используя Модель Управляемого объекта во Время выполнения. Словарь замены должен содержать ключи для всех переменных, определенных в шаблоне; если Вы хотите протестировать на нулевое значение, необходимо использовать NSNull объект — видит Используя Предикаты.

Перечисление 2  Используя выборку запрашивает шаблон

NSManagedObjectModel *model = <#Get a model#>;
NSError *error = nil;
NSDictionary *substitutionDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
    @"Fiona", @"FIRST_NAME", @"Verde", @"LAST_NAME",
    [NSDate dateWithTimeIntervalSinceNow:-31356000], @"DATE", nil];
NSFetchRequest *fetchRequest =
    [model fetchRequestFromTemplateWithName:@"PublicationsForAuthorSinceDate"
            substitutionVariables:substitutionDictionary];
NSArray *results =
    [aManagedObjectContext executeFetchRequest:fetchRequest error:&error];

Если шаблон не имеет переменных замены, Вы должны также:

  1. Использовать fetchRequestFromTemplateWithName:substitutionVariables: и передача nil как параметр переменных; или

  2. Использовать fetchRequestTemplateForName: и copy результат.

    При попытке использовать запрос выборки, возвращенный fetchRequestTemplateForName:, это генерирует исключение (»Can't modify a named fetch request in an immutable model").

Локализация модели управляемого объекта

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

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

Табличные 1  Ключи и значения в словаре локализации для модели управляемого объекта

Ключ

Значение

Примечание:

"Entity/NonLocalizedEntityName"

"LocalizedEntityName"

"Property/NonLocalizedPropertyName/Entity/EntityName"

"LocalizedPropertyName"

1

"Property/NonLocalizedPropertyName"

"LocalizedPropertyName"

"ErrorString/NonLocalizedErrorString"

"LocalizedErrorString"

Примечание: (1) свойства For в различных объектах с тем же нелокализованным именем, но который должен иметь различные локализованные имена.

Можно получить доступ к словарю локализации с помощью метода localizationDictionary. Отметьте, однако, это в реализации в версии 10.4 OS X, localizationDictionary может возвратиться nil пока Базовые Данные лениво не загружают словарь в своих собственных целях (например, сообщая о локализованной ошибке).

Строковый файл

Самый простой способ локализовать модель состоит в том, чтобы создать соответствующий строковый файл — строковое имя файла совпадает с именем файла модели, но с a .strings вместо a .xcdatamodel расширение (например, для файла модели назван MyDocument.xcdatamodel соответствующий строковый файл MyDocumentModel.strings— если Ваше имя файла модели уже включает суффикс «Модель», необходимо добавить дальнейшую «Модель», таким образом, строковое соответствие файла JimsModel.xcdatamodel был бы довольно маловероятно выглядящий JimsModelModel.strings). Формат файла подобен строковому файлу стандарта, который Вы используете для локализации (см. Строковые ресурсы Локализации), но ключ и оценивает образец, следует за показанным в Таблице 1.

Строковый файл для модели, включающей объект сотрудника, мог бы содержать следующее:

"Entity/Emp" = "Employee";
"Property/firstName" = "First Name";
"Property/lastName" = "Last Name";
"Property/salary" = "Salary";

Установка словаря локализации программно

Можно установить словарь локализации во время выполнения с помощью NSManagedObjectModel метод setLocalizationDictionary:. Необходимо создать словарь с ключами и значениями как показано в Таблице 1, и связать ее с моделью. Необходимо гарантировать, чтобы Вы сделали это, прежде чем модель будет использоваться, чтобы выбрать или создать управляемые объекты, потому что модель только для чтения после выполнения так. Перечисление, показанное в Перечислении 3, иллюстрирует создание в коде модели управляемого объекта включая словарь локализации. Объект называет «Выполнением» и представляет во время выполнения класс Выполнения. Объект имеет два атрибута, «дату» и «processID» — дата и целое число соответственно. ID процесса имеет ограничение, что его значение не должно быть меньше, чем нуль.

Перечисление 3  , Создающее модель управляемого объекта в коде

NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] init];
NSEntityDescription *runEntity = [[NSEntityDescription alloc] init];
[runEntity setName:@"Run"];
[runEntity setManagedObjectClassName:@"Run"];
[mom setEntities:@[runEntity]];
 
NSMutableArray *runProperties = [NSMutableArray array];
 
NSAttributeDescription *dateAttribute = [[NSAttributeDescription alloc] init];
[runProperties addObject:dateAttribute];
[dateAttribute setName:@"date"];
[dateAttribute setAttributeType:NSDateAttributeType];
[dateAttribute setOptional:NO];
 
NSAttributeDescription *idAttribute= [[NSAttributeDescription alloc] init];
[runProperties addObject:idAttribute];
[idAttribute setName:@"processID"];
[idAttribute setAttributeType:NSInteger32AttributeType];
[idAttribute setOptional:NO];
[idAttribute setDefaultValue:@0];
 
NSPredicate *validationPredicate = [NSPredicate predicateWithFormat:@"SELF >= 0"];
NSString *validationWarning = @"Process ID < 0";
[idAttribute setValidationPredicates:@[validationPredicate]
    withValidationWarnings:@[validationWarning]];
 
[runEntity setProperties:runProperties];
 
NSDictionary *localizationDictionary = @{
    @"Property/processID/Entity/Run" : @"Process ID",
    @"Property/date/Entity/Run" : @"Date"
    @"ErrorString/Process ID < 0" : @"Process ID must not be less than 0" };
[mom setLocalizationDictionary:localizationDictionary];