Повторное использование UIViewController для модальных и немодальных ситуаций

StackOverflow https://stackoverflow.com/questions/1652801

Вопрос

У меня есть 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. Но в любом случае установка часто изолируется от этого одного метода, и вызывающая сторона обрабатывает его одинаково в каждом случае.

    scroll top