Подтвердить что ты не робот

Как получить managedObjectContext для viewController, кроме получения его из appDelegate?

Недавно я узнал, что "вам действительно не нужно обращаться к AppDelegate, чтобы получить контекст управляемого объекта". Apple также внесла эту рекомендацию в свою документацию здесь. Это происходит следующим образом:

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

Далее они упоминали о некоторых других способах получения контекста. Пока я не могу понять, что они там говорят. Может кто-нибудь, пожалуйста, осветить проблему. Любые вспомогательные утверждения фрагмента кода приветствуются.

ИЗМЕНИТЬ

Иногда, однако, проще или более контекст где-то, кроме приложения или документа, или просмотрите контроллер. Несколько объектов, которые вы можете использовать в базе данных на основе данных приложение сохраняет ссылку на контекст управляемого объекта. Управляемый сам объект имеет ссылку на свой собственный контекст, как и различные объекты контроллера, которые поддерживают базовые данные, такие как массив и объект контроллеры (NSArrayController и NSObjectController в OS X и NSFetchedResultsController в iOS).

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

Что это такое? Уверен, что он не похож на высоко проголосовавший ответ ниже. Может ли кто-нибудь помочь мне понять эту часть документов Apple?

4b9b3361

Ответ 1

Он называется инъекцией зависимостей. В принципе, вызывающий/конструктор должен устанавливать NSManagedObjectContext на вызываемый/построенный.

В AppDelegate вы должны установить NSManagedObjectContext в rootViewController, который связан с UIWindow.

Затем ваш rootViewController должен установить NSManagedObjectContext в следующий контроллер представления и т.д.

Как? Это просто прост в классе контроллера вида, а вызывающий использует:

[nextViewController setManagedObjectContext:[self managedObjectContext]];

Некоторые другие могут рекомендовать синглтон, но это еще одна глубокая темная яма, которую лучше всего избегать.

Update

Инъекция зависимостей - лучший подход.

Это подход, разработанный Apple. Другой выбор включает в себя некоторую форму singleton: AppDelegate или другой.

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

Это совершенно другая проблема, и она не будет решена с несколькими экземплярами NSManagedObjectContext. Фактически, несколько экземпляров ухудшат ситуацию и гарантируют слияние конфликтов.

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

Это правильный ответ на эту проблему.

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

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

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

В этой ситуации вы рискуете конфликтом слияния, и вам нужно закодировать ситуацию. Первый шаг - изменить политику слияния в экземплярах NSManagedObjectContext.

Update

Я подозреваю, что вы неправильно читаете эту документацию.

То, что описывается, это возможность получить NSManagedObjectContext из экземпляра NSManagedObject. Это абсолютно полезно. Возьмите, например, контроллер вида, который имеет возможность добавлять или редактировать объект. Нажимая только NSManagedObject на контроллер вида, вы можете контролировать и решать, к чему будет обращаться этот контроллер. Контроллер получающего представления знает, что он должен разрешить редактирование полученного NSManagedObject. Неважно, с чем работает NSManagedObjectContext. Он может работать с основным, он может работать с ребенком, он может быть изолирован в unit test, ему не нужно знать или ухаживать. Он просто отображает данные из NSManagedObject, которые он передал, и сохраняет связанный NSManagedObjectContext, если пользователь решает сохранить изменения.

Эта документация НЕ предполагает наличие какого-либо универсального местоположения для вашего NSManagedObjectContext, чтобы жить (ака одноэлемент). Предполагается, что если у вас есть другой способ доступа к NSManagedObjectContext, который связан с NSManagedObject, что это нормально, и это определенно имеет смысл сделать.

Ответ 2

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

Используя однонаправленный "DataManager" класс, который содержит все методы инициализации основных данных с общедоступными ссылками на модель управляемого объекта и контекст, я могу получить данные, импортировав мой класс "DataManager.h" и звонки в одноэлемент:

// I have a method to create an object that requires the Manage Object Context, so I call it from the DataManager singleton
SomeObject *newObject = [SomeObject createObjectInContext:[[DataManager sharedInstance] managedObjectContext]];

// I have a method in DataManager to save the context
[[DataManager sharedInstance] saveContext];

Это фактически упрощенная версия. Обычно я использую вложенные Контексты Управляемых объектов, так что мой основной Контекст Управляемого Объекта не изменяется до тех пор, пока пользователь не подтвердит добавление или изменение Управляемого Объекта. Эта сложность может содержаться в классе "DataManager".

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

http://www.cocoanetics.com/2012/07/multi-context-coredata/