Описание тега nsmanagedobjectcontext

Экземпляр NSManagedObjectContext представляет собой единое "объектное пространство". Его основная ответственность - управлять набором управляемых объектов. Эти объекты образуют группу связанных объектов модели, которые представляют внутренне согласованное представление одного или нескольких постоянных хранилищ. Один экземпляр управляемого объекта существует в одном и только одном контексте, но несколько копий объекта могут существовать в разных контекстах. Доступно в iOS 3.0 и новее в CoreData.

Экземпляр NSManagedObjectContext представляет собой единое "пространство объектов" или блокнот в приложении. Его основная ответственность - управлять набором управляемых объектов. Эти объекты образуют группу связанных объектов модели, которые представляют внутренне согласованное представление одного или нескольких постоянных хранилищ. Один экземпляр управляемого объекта существует в одном и только одном контексте, но несколько копий объекта могут существовать в разных контекстах. Таким образом, уникальность объекта ограничена определенным контекстом.

Управление жизненным циклом Контекст - это мощный объект, играющий центральную роль в жизненном цикле управляемых объектов, с обязанностями от управления жизненным циклом (включая сбой) до проверки, обработки обратной связи и отмены / повтора. С помощью контекста вы можете извлекать или "извлекать" объекты из постоянного хранилища, вносить изменения в эти объекты, а затем либо отменить изменения, либо - опять же через контекст - зафиксировать их обратно в постоянное хранилище. Контекст отвечает за отслеживание изменений в своих объектах и ​​поддерживает диспетчер отмены, чтобы вы могли более детально контролировать отмену и повтор. Вы можете вставлять новые объекты и удалять те, которые вы выбрали, и фиксировать эти изменения в постоянном хранилище.

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

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

До OS X v10.7 и iOS v5.0 родительское хранилище всегда было постоянным координатором хранилища. В OS X v10.7 и новее и iOS v5.0 и новее родительским хранилищем может быть другой контекст управляемого объекта. В конечном счете, корнем предков контекста должен быть постоянный координатор хранилища. Координатор предоставляет управляемую объектную модель и отправляет запросы в различные постоянные хранилища, содержащие данные.

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

Выполнение фоновых операций во втором потоке или очереди.

Управление отменяемыми изменениями, например в окне инспектора или в представлении.

Как следует из первого сценария, родительский контекст может обслуживать запросы от дочерних элементов в разных потоках. Следовательно, вы не можете использовать родительские контексты, созданные с типом ограничения потока (см. Параллелизм).

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

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

[[NSNotificationCenter defaultCenter] addObserver:self
                                      selector:@selector(<#Selector name#>)
                                      name:NSManagedObjectContextDidSaveNotification
                                      object:<#A managed object context#>];

Некоторые системные фреймворки внутренне используют Core Data. Если вы зарегистрируетесь для получения этих уведомлений из всех контекстов (передав nil в качестве параметра объекта такому методу, как addObserver: selector: name: object:), вы можете получать неожиданные уведомления, которые трудно обрабатывать.

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

В OS X v10.7 и более поздних версиях и IOS v5.0 и позже, при создании контекста можно указать шаблон параллелизма, с которым вы будете использовать его с помощью initWithConcurrencyType:. Когда вы создаете контекст управляемого объекта с помощью initWithConcurrencyType:, у вас есть три варианта ассоциации его потока (очереди).

Конфайнмент ( NSConfinementConcurrencyType)

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

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

Частная очередь ( NSPrivateQueueConcurrencyType)

Контекст создает частную очередь и управляет ею.

Основная очередь ( NSMainQueueConcurrencyType)

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

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

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

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

Если ваш код выполняется в основном потоке, вы можете напрямую вызывать методы в контекстах стиля основной очереди вместо использования блочного API.

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

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

__block NSError *error;
__block BOOL savedOK = NO;
[myMOC performBlockAndWait:^{
    // Do lots of things with the context.
    savedOK = [myMOC save:&error];
}];

Вы также можете выполнять другие операции, например:

NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
__block NSUInteger rCount = 0;

[context performBlockAndWait:^() {
    NSError *error;
    rCount = [context countForFetchRequest:fr error:&error];
    if (rCount == NSNotFound) {
        // Handle the error.
    } }];
NSLog(@"Retrieved %d items", (int)rCount);

Замечания о создании подклассов. Вам категорически не рекомендуется создавать подклассы NSManagedObjectContext. Механизмы отслеживания изменений и управления отменой в высшей степени оптимизированы и, следовательно, сложны и деликатны. Внедрение вашей собственной дополнительной логики, которая может повлиять на processPendingChanges, может иметь непредвиденные последствия. В таких ситуациях, как миграция магазина, Core Data создаст экземпляры NSManagedObjectContext для собственного использования. В этих обстоятельствах вы не можете полагаться ни на какие функции своего пользовательского подкласса. Любой подкласс NSManagedObject всегда должен быть полностью совместим с NSManagedObjectContext (то есть, он не может полагаться на функции подкласса NSManagedObjectContext).