Описание тега nsmanagedobjectcontext
Экземпляр 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).