Повторное использование UIViewController для модальных и немодальных ситуаций
-
22-07-2019 - |
Вопрос
У меня есть UIViewController & # 8212; давайте назовем это «FormController» & # 8212; это просто форма, которая редактирует объект. Я хочу использовать его в 2 разных ситуациях:
<Ол> Создание нового объекта & # nbsp; с использованием метода presentModalViewController:
метода UINavigationController.
Редактирование существующего объекта & nbsp; поместите контроллер представления в стек UINavigationController, не используя метод диалога.
Есть небольшая разница в том, что в модальной ситуации мне бы хотелось иметь панель инструментов с " Отмена " и " Готово " кнопки, тогда как в ситуации со стеком я хотел бы просто иметь панель навигации, предоставляемую UINavigationController. Р>
Это будет похоже на приложение «Контакты», в котором «Новый контакт» и " Изменить контакт " Похоже, что на экранах используется тот же контроллер представления, но форма «Новый контакт» представляется модально, а экран «Правка» помещается в стек навигации.
Мой вопрос: каков наилучший способ справиться с обеими ситуациями без необходимости писать 2 отдельных, но в основном идентичных контроллера вида?
Я думал о создании " ModalFormController " который инкапсулирует голый «FormController» через композицию и добавляет панель инструментов, но я где-то читал в документах, что Apple не рекомендует вкладывать контроллеры представления.
Решение
То, что я делаю (иногда), настраивает enum
, который указывает тип контроллера представления. Р>
Например, у вас может быть два типа: тип Edit
и тип Add
(" new "). Р>
Тип Add
реализуется через модальный контроллер представления, а тип Edit
помещается в существующий стек навигации.
В методе -viewDidLoad:
контроллера представления я просто создаю дерево switch / case
, которое устанавливает заголовок и другие характеристики внешнего вида в зависимости от перечисления типов, указанного выше . р>
Приятно то, что легко добавить новый тип. Недостатком является то, что условное дерево для обработки этого перечисления может быстро усложниться, в зависимости от того, насколько различны типы. Р>
Но дерево switch / case
упрощает управление.
Итак, это зависит от того, что вы пытаетесь сделать с двумя типами. Но это определенно выполнимо.
Другие советы
Почему бы не использовать подклассы? Сделайте ModalCreateFormController
подклассом EditFormController
и обработайте специфические для модальных вещей вещи в подклассе.
Помимо наличия явного свойства в контроллере представления (как предполагает Алекс Рейнольдс), мне приходят на ум два других подхода:
<Ол>Если у вас есть какой-то объект модели, который вы редактируете, спросите его о его текущем состоянии. Если он когда-либо был сохранен, то вы находитесь в режиме редактирования. В противном случае вы находитесь в режиме создания.
Посмотрите на значение свойства контроллера parentViewController
. Если это экземпляр UINavigationController
, то вы находитесь в стеке навигации. Если вы отображаетесь модально, это будет экземпляр вашего контроллера списков.
Мм, я ненавижу лишние ивары ...
Я использую это вместо:
if([[self.navigationController viewControllers] objectAtIndex:0] == self){
//Modal
}else{
//Pushed
}
Это что-то вроде хака, но мы используем логику, что если нарушающий контроллер представления является первым в стеке, вы не можете вернуться назад. На самом деле мы игнорируем тот факт, отображается ли он модально вообще.
Мне приходилось делать это несколько раз в моем приложении, и после нескольких попыток сделать это, включая модальные подклассы & amp; повторно используемые модальные вспомогательные классы, которые использовали forwardInvocation. Я обнаружил, что наилучшим способом было создать метод содержащийModalViewController для каждого контроллера представления, который (обычно) создает и возвращает UINavigationController для вызывающей стороны для использования с presentModalViewController.
В большинстве случаев этот метод создает и возвращает UINavigationController с self в качестве корневого контроллера представления (с повторными вызовами метода, проверяющими self.navigationController и возвращающими его вместо этого, если он не равен nil). В других случаях я сначала сделал фиктивный корневой контроллер и нажал себя на втором, чтобы получить кнопку возврата. Затем можно использовать хитрость, чтобы поймать нажатие кнопки «назад»: http: // smallduck .wordpress.com / 2010/10 / 05 / перехватывать-UINavigationController /
В некоторых случаях представление не нуждается в панели навигации, поэтому этот метод просто настраивает некоторые флаги и возвращает self. Я даже обнаружил, что в некоторых случаях нужна навигационная панель, было проще сделать так, чтобы этот метод вызывал self.view, затем настраивал иерархию представления, чтобы добавить UINavigationBar и снова возвращал self. Но в любом случае установка часто изолируется от этого одного метода, и вызывающая сторона обрабатывает его одинаково в каждом случае.