Можно ли использовать несколько NSUndoManagers с одним управляемым объектом Core-DataObjectContext?

//Правка: На самом деле, никто не имеет никаких предложений или соображений по этому поводу? Я почему-то задал вопрос? //

У моего iPhone-приложения есть один управляемый объект-объект с умеренно сложной моделью данных. Теперь я добавляю отмену функциональности и не понимаю, как лучше обрабатывать вложенные viewControllers (так как каждый уровень может изменить модель данных).

Apple docs указывают: "Рассмотрите приложение, которое отображает список книг и позволяет вам перейдите к подробному представлению, которое в свою очередь позволяет редактировать отдельные свойства книги (например, ее название, автор и дата авторских прав). Вы можете создать новую книгу из экран списка, перемещайтесь между двумя другие экраны для редактирования его свойств, затем вернитесь к оригиналу список. Это может показаться странным, если отменить операцию в виде списка unid изменение имени авторов, которое было сделал два экрана, а не удаляя всю книгу".


Так какой лучший способ реализовать это? В настоящее время я думаю, что каждый viewController сохраняет свой собственный undoManager, который будет активен всякий раз, когда он на экране. Поэтому я понимаю, что для этого потребуются следующие шаги (для каждого VC):

  • Добавить объект: myUndoManager
  • Добавьте метод undoManager, возвращающий myManagedObjectContext.undoManager;
  • В viewDidAppear: myManagedObjectContext.undoManager = myUndoManager;//создаем сначала, если nil
  • В viewWillDisappear: myManagedObjectContext.undoManager = nil;
  • Предупреждение по памяти: [self.undoManager removeAllActions ];
  • В dealloc: self.myUndoManager = nil;
  • Для каждого изменения модели: [self.undoManager setActionName:NSLocalizedString(@"XXX",@"")];
  • CoreData будет обрабатывать фактические сообщения отменить/повторить.

Кроме того, я должен оставаться первымResponder:

  • В viewDidAppear: `[self getFirstResponder] '
  • Добавить метод canBecomeFirstResponder, возвращающий YES
  • В viewWillDisappear: [self resignFirstResponder];
  • Снова включить firstResponder при сходе в подвид (например, textFields)

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

  • Во-первых, это лучшая практика для реализации отмены нескольких VC?
  • У меня возникнут проблемы с моим дочерним VC, которые не выполняют свои отскоки до моего выполнения моих предыдущих?
  • Если это так, отображает ли этот список все, что мне нужно сделать?
  • Будет ли запущен ManagedObjectContext с запущенным несколькими UndoManagers?
  • Нужно ли мнезывать ProcessPendingActions перед заменой undoManager?

Ответ 1

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

Скажем, у вас 3 уровня. Уровень 1 представляет всю запись, уровень 2 представляет собой подмножество данных с уровня 1, а уровень 3 представляет собой подмножество данных с уровня 2.

Как только вы вернетесь из уровня 3, вы в основном сказали Я принимаю, и вам не нужно отменять ни одну из этих данных на уровне 2. Эти измененные данные должны отображаться только как прочитанные - только данные на уровне 2, если они вообще отображаются. Точно так же, как только вы вернетесь из уровня 2, вы должны освободить его менеджера отмены.

Вернитесь на уровень 1, так как он представляет всю запись, почему бы не нажать кнопку "Отмена", а не пытаться отменить (или в дополнение к тому, что делает ваш контроллер уровня 1)?

Затем, если вы хотите отменить все операции, вы можете отправить в контекст управляемых объектов сообщение следующего типа:

[myMOC refreshObject:theEditedObject mergeChanges:NO];

Это приведет к эффективному откату всей записи .

Если по какой-либо причине вы решили оставить диспетчер отмены 3-го уровня, пока вы находитесь на уровне 2, и вы выполняете откат на уровне 2, только данные, относящиеся к диспетчеру отмены уровня 2, будут отброшены назад. Диспетчер отмены 3-го уровня является отдельным, а Core Data не отображает менеджеров отмены в качестве вложенных.

Контекст управляемых объектов не может запутаться из-за нескольких менеджеров отмены, поскольку он может отслеживать только один за раз с помощью метода setUndoManager:.

Вам, вероятно, не понадобится использовать processPendingChanges, если пока не произойдет откат до завершения цикла событий после внесения изменений. Я бы не стал беспокоиться об этом, если ваше отмена не восстановит некоторые данные, которые должны быть записаны с менеджером отмены до этой точки.

Ответ 2

Я бы очень много работал, чтобы иметь только одного менеджера отмены.
рассмотрим сценарий:

модель: (курица)
свойства: яйца, цвет, размер;

модель: (яйцо)
свойства: курица, цвет;

chicken.eggs = отношение одного к многим к яйцу, обратное верно для egg.chicken.

вы создаете 2 менеджера отмены для одного из chickenViewController и один для eggViewController.
вы создаете курицу0 и ее яйца: egg0, egg1.
вы создаете курицу1 и ее яйца: egg2, egg3.
вы удаляете egg2.

теперь вы удаляете кубик 1 каскадом, удаляющим яйца.
теперь вы возвращаетесь к eggViewController и отменяете... что вы хотите (исключение произойдет).
теперь вы отмените chickenViewController и курицу1, и яйца вернутся, но есть ли 2 яйца?

Edit Я немного смягчаю свой тон, предполагая, что вы используете иерархическую структуру представлений, такую ​​как UINavigationController, и каждый раз, когда вы переходите к дочернему виду, вы создаете новый контроллер Undo, я не уверен, что у вас должна быть проблема.

Ответ 3

Похоже, вы хотите взять кучу отменить в один кусок, чтобы их можно было отменить как группу. Это достигается с помощью beginUndoGrouping и endUndoGrouping. Есть ли причина, по которой вы не можете это использовать? Я не уверен, что вы можете отменить один шаг посередине группы, так что это будет проблемой.