Как отклонить модальный код, который был представлен в UIStoryboard с модальным отступлением?
Настройка: у меня установлена раскадровка с двумя простыми контроллерами вида A и B. В A есть кнопка, которая переходит в B с модальным сегментом. B представлен модальный переход сверху A. Его тонкий.
Вопрос: есть ли способ выскочить B и вернуться к A с помощью некоторой простой магии раскадровки?
Обратите внимание, что если все это было в контроллере навигации, и я использовал push-сег, он неявно должен был быть рассмотрен навигационным контроллером. Будет кнопка "назад". Theres ничего сопоставимого для модалов, мне нужно создать UI сам, что хорошо, но мне интересно, есть ли механик segue, который я могу использовать для сигнала, чтобы вернуться с B на A.
Теперь метод oldskool для построения возврата из B в будет:
- создать свойство делегата в B
- set A является делегатом B, когда воспроизводится модальный переход segue (я могу подключиться к этому с помощью метода prepareForSegue: sender: in As)
- когда его время отклоняется, сигналы B передаются его делегату
- A реализует метод делегата, который отклоняет B
Это работает, но чувствует себя слишком много накладных и глупых.
Есть ли какой-то механик UIStoryboard, который я пропустил, что в основном будет делать "обратный модальный сегмент"?
Ответы
Ответ 1
Нет никакой магии раскадровки для отклонения модального контроллера представления, не записывая хотя бы немного кода.
Но пока вам нужно реализовать какой-то собственный код, вам необязательно идти на эти проблемы. Вы можете просто нажать кнопку в контроллере B, который вызывает [self dismissViewControllerAnimated:YES completion:nil]
. (Документы говорят, что диспетчер представления представления должен быть уволен, но они также говорят, что сообщение будет перенаправлено контроллеру представления представления, если он вызывается присутствующим. Если вы хотите быть более откровенным в этом вопросе, в некоторых случаях, например, когда один контроллер модального представления представлен от другого - вы можете явно ссылаться на презентатора с помощью self.presentingViewController
и вызывать dismiss...
оттуда.)
Вы видите делегирование бизнеса в некоторых приложениях, потому что это один из способов уведомления контроллера вида A о том, что сделал пользователь во время просмотра контроллера B... но это не единственный способ. Там KVO, уведомления или просто вызов методов A после ссылки на него с помощью self.presentingViewController
(предполагая, что B всегда знает, что он представлен A). И если A не нужно знать о том, что произошло в B (скажем, потому что пользователь нажал кнопку "Отмена" ), нет необходимости делать что-либо из этого - вы можете просто отказаться от модальности и сделать с ним.
В iOS 6 и более поздних версиях unind segues добавляет еще один вариант, предоставляя немного "магии раскадровки" для отклонения контроллеров модального представления (или иначе "отступающих" от последовательности segues). Но этот подход по-прежнему требует некоторого кода - вы не можете установить его полностью в раскадровке. Однако с положительной стороны этот код предоставляет путь для получения информации от диспетчера представлений, который отклоняется (B), к тому, который представил его (A).
Apple имеет техническую ноту об отключении segues, которая подробно описывает их, но здесь короткая версия:
-
Определите метод IBAction
в классе контроллера вида, который хотите развернуть, - тот, который представляет собой контроллер модального представления, а не сам контроллер модального представления (контроллер просмотра A в вашем вопросе). В отличие от обычных методов IBAction
, они должны принимать параметр типа UIStoryboardSegue *
; например.
- (IBAction)unwindToMainMenu:(UIStoryboardSegue*)sender
-
В представленном контроллере представления (B в вопросе) проведите элемент управления к зеленому значку выхода и выберите метод, который вы определили.
-
В вашей реализации метода разматывания вы можете обратиться к segue sourceViewController
, чтобы получить информацию с отклонения диспетчера представлений. Вам не нужно вызывать dismissViewControllerAnimated:completion:
, потому что segue обрабатывает отклонение контроллера вида, который уходит.
Ответ 2
Там есть маска раскадровки для достижения этой цели. Он известен как развязка. В файле .h вы реализуете всевозможные методы стиля "целевого действия", которые вам нужны, но сколько раз вам нужно. Для модального, обычно два (отменить и сохранить). Поэтому в моем файле A.h я бы добавил:
// A.h file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue;
- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue;
Теперь, в вашем раскадровке, если у вас есть segue от A до B. Теперь вы можете выполнить перетаскивание стиля стиля "целевое действие" с кнопок отмены/сохранения в B до зеленого значка "Выход" в нижней части контроллер B в вашем раскадровке. Когда вы это сделаете, Xcode подберет два метода, которые мы создали (поскольку они находятся в файле заголовка A, и они имеют правильную подпись (например, IBAction и UIStoryboardSegue *.), А B - это место назначения из A) Итак, там у вас это есть. У вас есть волшебство раскадровки, которое вы искали!
В реализации двух обратных вызовов у вас будет что-то вроде:
// A.m file
- (IBAction)myCancelUnwindSegueCallback:(UIStoryboardSegue *)segue {
UIViewController *modalGoingAway = segue.sourceViewController;
// Do something (like get data) from modalGoingAway if you need to...
}
- (IBAction)mySaveUnwindSegueCallback:(UIStoryboardSegue *)segue {
UIViewController *modalGoingAway = segue.sourceViewController;
// Do something (like get data) from modalGoingAway if you need to...
}
Наконец, если этот подход удовлетворит ваши потребности, отлично. Все готово. Тем не менее, я все еще подключаю весь шаблон делегирования протокола /dataSource, если "on cancel" или "on save". Я хочу выполнить некоторые операции с частными свойствами B, прежде чем передавать управление A, чтобы удалить B из иерархии представлений.