Использование управляемых объектов Core Data в среде Cocoa, Mac OS, iOS

Cocoa

Доступ и изменение свойств

Core Data автоматически генерирует эффективные public и primitive методы get и set для доступа к моделируемым свойствам (атрибутам и связям) управляемых классов объектов (см. раздел «Методы акцессоры управляемых объектов"). Когда вы получаете доступ или изменяете свойства управляемого объекта, Вы должны использовать эти методы напрямую.

Большинство отношений двунаправленные. Любые изменения, внесенные в отношения между объектами должны поддерживать целостность объекта графа.

Атрибуты и отношения один-к-одному

Получение доступа к атрибутам и отношениям один к одному производится с помощью стандартных методов акцессоров или с использованием синтаксиса точки Objective-C.

NSString *firstName = [anEmployee firstName];
Employee *manager = anEmployee.manager;

Кроме того, вы можете использовать как стандартные методы доступа так и синтаксис с точкой для изменения атрибутов, например:

newEmployee.firstName = @"Стиг";
[newEmployee setManager:manager];

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

[[aDepartment manager] setSalary:[NSNumber numberWithInteger:1000]];
aDepartment.manager.salary = [NSNumber numberWithInteger:1000];

Вы можете также использовать кодирование ключ-значение (KVC), чтобы получить или установить значение простого атрибута, как показано в следующем фрагменте кода. Использование KVC, значительно менее эффективно, чем использование методов доступа, так что вы должны использовать KVC только при необходимости (например, при выборе кнопки или динамически).

[newEmployee setValue:@"Стиг" forKey:@"firstName"];
[aDepartment setValue:[NSNumber numberWithInteger:1000] forKeyPath:@"manager.salary"];

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

NSMutableString *mutableString = [NSMutableString stringWithString:@"Стиг"];
[newEmployee setFirstName:mutableString];
[mutableString setString:@"Лаура"];

В данном примере создается изменяемый объект, который затем присваивается атрибуту firstName, но реализация setFirstName, по умолчанию, не делает копию данных объекта, а лишь сохраняет ссылку на него, следовательно последующее изменение переданного объекта приведет к изменению и значения атрибута, в данном случае следовало-бы реализовать собственный метод сеттер атрибута с операцией копирования значения (copy).

Отношения ко многим

Чтобы получить доступ к отношениям ко-многим (будь то отношение один-ко-многим или многие-ко-многим), можно использовать стандартные get методы доступа. Отношение ко-многим представляется набором, как показано в следующем фрагменте кода:

NSSet *managersPeers = [managersManager directReports];
NSSet *departmentsEmployees = aDepartment.employees;

Можно в принципе управлять всем отношением ко-многим таким же образом, как и к-одному, либо с помощью специального метода доступа, или (что более вероятно) кодирования ключ-значение, как показано в следующем примере.

NSSet *newEmployees = [NSSet setWithObjects:employee1, employee2, nil];
[aDepartment setEmployees:newEmployees];

NSSet *newDirectReports = [NSSet setWithObjects:employee3, employee4, nil];
manager.directReports = newDirectReports;

Обычно, нет необходимости, в том, чтобы устанавливать все отношения сразу, а только необходимо добавить или удалить один элемент за раз. Чтобы сделать это, надо использовать mutableSetValueForKey: или один из автоматически генерируемых для отношения методов мутаторов.

NSMutableSet *employees = [aDepartment mutableSetValueForKey:@"employees"];
[employees addObject:newEmployee];
[employees removeObject:firedEmployee];

// или

[aDepartment addEmployeesObject:newEmployee];
[aDepartment removeEmployeesObject:firedEmployee];

Важно понимать разницу между значениями, возвращаемыми с точкой доступа и mutableSetValueForKey:. mutableSetValueForKey: возвращает изменяемый объект прокси. Если вы изменяете его содержимое, он будет посылать соответствующему ключ-значение наблюдению (KVO) уведомления об изменениях в отношениях. Точка доступа, просто возвращает набор. Если вы управляете множеством как показано в этом фрагменте кода:

[aDepartment.employees addObject:newEmployee]; // не делайте так!

После уведомления KVO изменений не генерируются и обратные связи не обновляются правильно.

Напомним, что точка просто вызывает метод доступа, так что по тем же причинам:

[[aDepartment employees] addObject:newEmployee]; // не делайте этого!

Сохранение изменений

Изменение управляемого объекта не вызывает изменений которые будут сохранены в хранилище. Контекст управляемого объекта выступает в качестве блокнота. Вы можете создать и зарегистрировать управляемые объекты с ним, вносить изменения в объекты, производить отмены и повторы изменений, как вы хотите. Если вы вносите изменения в управляемые объекты, связанные с данным контекстом, эти изменения остаются локальными в этом контексте пока вы не зафиксируете изменения, отправив контексту save: сообщение. В этот момент, при условии, что не существует никаких ошибок валидации, изменения фиксируются в хранилище. Как следствие, просто создание управляемого объекта не заставит его сохраниться в постоянном хранилище, и удаление управляемого объекта не вызывает запись на удаление из хранилища, необходимо сохранить контекст для фиксации изменений.

Идентификаторы и идентификаторы URI управляемого объекта

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

NSManagedObjectID *moID = [managedObject objectID];

Есть две формы объекта ID. Когда управляемый объект создается впервые, Core Data присваивает ему временный ID, только если он сохраняется в постоянном хранилище, Core Data назначит управляемому объекту постоянный ID. Вы можете легко выяснить, действительно ли ID временный:

BOOL isTemporary = [[managedObject objectID] isTemporaryID];

Вы также можете преобразовать идентификатор объекта в URI представление:

NSURL *moURI = [[managedObject objectID] URIRepresentation];

Учитывая ID управляемого объекта или URI, вы можете получить соответствующий управляемый объект с помощью managedObjectIDForURIRepresentation: или objectWithID:.

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

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

Иногда вы можете извлечь выгоду из создания собственного уникального идентификатора (UUID) свойства, которое может быть определено и установлено для вновь добавленных объектов. Это позволяет эффективно находить конкретные объекты, используя предикаты (хотя до операции сохранения новые объекты могут быть найдены только в их оригинальном контексте).

Копирование и Copy и Paste

Трудно решить проблему копирования или поддержку копирования и вставки, в общем виде для управляемых объектов. Вы должны определить в каждом конкретном случае на индивидуальной основе, какие свойства управляемого объекта, вы на самом деле хотите скопировать.

Копирование атрибутов

Если вы просто хотите скопировать атрибуты управляемого объекта, то во многих случаях лучшей стратегией может быть операция копирования для создания словаря (списка свойств) представления управляемого объекта, а в операции вставки, создать новый управляемый объект и заполнить его с помощью словаря. Вы можете использовать ID управляемого объекта (описанный в "Идентификаторы и идентификаторы URI управляемого объекта") с поддержкой копирования и вставки. Заметим, однако, что техника должна быть адаптирована для обеспечения копирования новых объектов.

Новый, несохраненный, управляемый объект имеет временный ID. Если пользователь выполняет операцию копирования, а затем операцию сохранения, ID управляемого объекта измененится и ID записанный в копии будет недействительным в последующей эксплуатации операции вставки. Чтобы обойти эту проблему, можно использовать "отложенную запись". В операции копирования, вы объявляете пользовательские типы, ID управляемого объекта временно не записываете, но вы сохраняете ссылку на оригинальный управляемый объект. В pasteboard:provideDataForType: методе вы затем записываете идентификатор текущего объекта.

В дальнейшем вполне возможны осложнения, потому, что ID по прежнему во временной операции вставки, но вы все равно должны допускать возможность будущих операций вставки после промежуточной операции сохранения. Поэтому вы должны повторно объявить тип , чтобы установить вставку снова, в противном случае вставка сохранит временный ID. Вы не можете вызвать addTypes:owner: во время pasteboard:provideDataForType:, так что вы должны использовать задержку выполнения, например:

- (void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
{
    if ([type isEqualToString:MyMOIDType]) {
        // Предположим, cachedManagedObject является объектом первоначально скопированым
        NSManagedObjectID *moID = [cachedManagedObject objectID];
        NSURL *moURI = [moID URIRepresentation];
        [sender setString:[moURI absoluteString] forType:MyMOIDType];
        if ([moID isTemporaryID]) {
            [self performSelector:@selector(clearMOIDInPasteboard:)
                    withObject:sender afterDelay:0];
        }
    }

    // дальнейшая реализация...

}

- (void)clearMOIDInPasteboard:(NSPasteboard *)pb
{
    [pb addTypes:[NSArray arrayWithObject:MyMOIDType] owner:self];
}

Копирование отношений

Если вы хотите скопировать отношения необходимо также рассмотреть объекты, связанные с их первым ярусом связанных объектов, если вы не будете осторожны, то возможно, что вы будете копировать весь граф объектов (которые могут быть не тем, что вы хотите!). Если вы хотите скопировать к-одному, вы должны решить, будет ли копия назначения новым объектом или ссылкой. Если это ссылка, то, что должно произойти, чтобы обратная связь с первоначальным объектом сделала копию и пересмотрела отношения между другими объектами? Вам нужно сделать аналогичные решения для ко-многим.

Drag and Drop

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

NSURL *moURI = [[managedObject objectID] URIRepresentation];

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

NSURL *moURL = // получаем из буфера обмена ...
NSManagedObjectID *moID = [[managedObjectContext persistentStoreCoordinator]
    managedObjectIDForURIRepresentation:moURL];
    
// считаем, что moID не-nil...

NSManagedObject *mo = [managedObjectContext objectWithID:moID];

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

Валидация

Структура Core Data обеспечивает чистую инфраструктуру для поддержки проверки, как с помощью логики заключенной в объектную модель, так и через пользовательский код. В модели управляемого объекта, можно задать ограничения на значения, которые могут иметь свойства (например, заработная плата работника не может быть отрицательной, или что каждый сотрудник должен принадлежать отделу). Есть две формы методов проверки, те, которые следуют стандартной конвенции ключ-значение кодирования, чтобы проверить значение для одного атрибута, и специального набора (validateForInsert:, validateForUpdate: и validateForDelete:) для проверки всего объекта на различных этапах его жизненного цикла (вставка, обновление и удаление). Последнее может быть особенно полезно для проверки комбинаций значений, например, чтобы гарантировать, что работник может быть введен в план покупки акций, только если его срок службы превышает заданную длинну и его класс оплаты находится на уровне или выше определенного уровня.

Модель на основе ограничений вызывает методы проверки автоматически до фиксирования в внешнем хранилище изменений, чтобы предотвратить сохраняение неверных данных. Вы также можете ссылаться на них программно когда это необходимо. Вы проверки отдельных значений с помощью validateValue:forKey:error:.Управляемый объект сравнивает новое значение с учетом ограничений, указанных в модели, и вызывает любой пользовательский метод проверки (в форме validate<Key>:error:), который вы реализовали. Даже если вы реализовали собственные методы проверки, вы обычно не должны называть собственные методы проверки непосредственно. Это гарантирует, что любые ограничения, определенные в модели управляемого объекта применяются.

Управление отменой (Undo)

Структура Core Data обеспечивает автоматическую поддержку отмены и повтора. Управление отменой распространяется даже на переходные свойства (свойства, которые не сохраняются в постоянном хранилище, но указанные в управляемой объектной модели).

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

Чтобы отменить операцию, вы просто высылаете контексту undo сообщение, а для отмены отправляете контексту redo сообщение. Вы также можете откатить все изменения, сделанные с момента последней операции сохранения используя rollback (это также очищает стек отмены) и сбросить контекст в свое базовое состояние с помощью reset.

Вы также можете использовать другие стандартные функциональные возможности менеджера отмены, такие группировки отмен. Core Data регистрирует в очереди до отмены и добавляет их в пакет (это позволяет framework-у объединять изменения, отбрасывать противоречивые изменения, а также выполнять ряд других операций, которые лучше работают задним числом, чем непосредственно). Если вы используете другие методы, помимо beginUndoGrouping и endUndoGrouping, обеспечьте, чтобы любая очередь операции правильно промывалась, Вы должны сначала посылать контексту управляемого объекта сообщение processPendingChanges.

Например, в некоторых ситуациях вы можете изменить, или, в частности, отключить, поведение отмены. Это может быть полезно, если вы хотите создать стандартный набор объектов при создании нового документа (но хотите убедиться, что документ не будет показан как загрязненный, когда он отображается), или если вам необходимо объединить новое состояние из другого потока или процесса. В общем, для выполнения операций без регистрации отмены, отправьте менеджеру отмены сообщений disableUndoRegistration, внеситеи изменения, а затем отправьте менеджеру отмены сообщение enableUndoRegistration. Перед каждым, вы посылаете сообщение контексту processPendingChanges, как показано в следующем фрагменте кода:

NSManagedObjectContext *moc = ...;
[moc processPendingChanges];  
[[moc undoManager] disableUndoRegistration];

//создайте изменения, которые не запишутся в операцию отмены

[moc processPendingChanges]; 
[[moc undoManager] enableUndoRegistration];
 
 
homeЗаметили ошибкукарта сайта 
   Made on a Mac