Отклонение представленного контроллера представления

117

У меня теоретический вопрос. Сейчас я читаю руководство Apple ViewController .

Они написали:

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

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

[self dismissViewControllerAnimated:NO completion:nil]?

Почему первый вариант лучше? Почему Apple рекомендует это?

никитахилы
источник

Ответы:

122

Я думаю, что Apple здесь немного прикрывает свои спины из-за потенциально громоздкого API.

  [self dismissViewControllerAnimated:NO completion:nil]

На самом деле это немного скрипка. Хотя вы можете - законно - вызвать это на представленном контроллере представления, все, что он делает, - это пересылает сообщение на контроллер представления представления. Если вы хотите сделать что-то сверх того, просто отклонив VC, вам нужно будет это знать, и вы должны относиться к нему так же, как к методу делегата - так как это в значительной степени то, что есть, запеченный несколько негибкий делегат метод.

Возможно, они столкнулись с множеством плохого кода, написанного людьми, не совсем понимающими, как это устроено, отсюда и их осторожность.

Но, конечно, если все, что вам нужно сделать, это отказаться от дела, продолжайте.

Мой собственный подход - это компромисс, по крайней мере, он напоминает мне, что происходит:

  [[self presentingViewController] dismissViewControllerAnimated:NO completion:nil]

[Swift]

  self.presentingViewController?.dismiss(animated: false, completion:nil)
Литейный завод
источник
26
Следует отметить, что использование presentingViewControllerв большинстве случаев бесполезно, так как оно будет относиться к UINavigationControllerif self, встроенному в него. В этом случае вы вообще не сможете получить presentingViewController. Тем не менее, [self dismissViewControllerAnimated:completion]в этом случае все еще работает. Я предлагаю продолжать использовать это, пока Apple не исправит это.
memmons 06
4
Мне нравится, что этот ответ все еще актуален 3 года спустя.
user1021430 01
1
Еще следует учитывать то, что контроллер представления не знает, как он был отображен. Он мог быть представлен, наложен на контроллер навигации, часть контроллера панели вкладок и т. Д. Использование делегата позволяет «представляющему» контроллеру представления «отклонить» контроллер представления, используя метод, обратный тому методу, который использовался для его представления.
Дэвид Смит
51

Обновлено для Swift 3

Я пришел сюда, просто желая отклонить текущий (представленный) контроллер представления. Я отвечаю всем, кто приходит сюда с той же целью.

Контроллер навигации

Если вы используете контроллер навигации, то это довольно просто.

Вернитесь к предыдущему контроллеру представления:

// Swift
self.navigationController?.popViewController(animated: true)

// Objective-C
[self.navigationController popViewControllerAnimated:YES];

Вернитесь к контроллеру корневого представления:

// Swift
self.navigationController?.popToRootViewController(animated: true)

// Objective-C
[self.navigationController popToRootViewControllerAnimated:YES];

(Благодаря этому ответу на Objective-C.)

Контроллер модального представления

Когда контроллер представления представлен модально, вы можете отклонить его (из второго контроллера представления), вызвав

// Swift
self.dismiss(animated: true, completion: nil)

// Objective-C
[self dismissViewControllerAnimated:YES completion:nil];

В документации говорится:

Контроллер представления представления отвечает за отклонение представленного контроллера представления. Если вы вызываете этот метод на самом контроллере представленного представления, UIKit просит контроллер представления обработать отклонение.

Таким образом, представленный контроллер представления вызывает его сам по себе. Вот полный пример.

Делегаты

Вопрос OP касался сложности использования делегатов для отклонения представления.

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

Suragch
источник
50

Это сделано для повторного использования контроллера представления.

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

Реализуя протокол, вы позволяете контроллеру родительского представления решать, как он должен быть представлен / отправлен и отклонен / извлечен.

Майкл Энрикес
источник
7

попробуй это:

[self dismissViewControllerAnimated:true completion:nil];
Осита Вималасурия
источник
6

По моему опыту, это пригодится, когда вам нужно отклонить его из любого ViewController, который вы хотите, и выполнить разные задачи для каждого контроллера просмотра, который отклоняет его. Любой viewController, использующий протокол, может отклонить представление по-своему. (ipad vs iphone, или передача разных данных при отклонении из разных представлений, вызов разных методов при отклонении и т. д.)

Редактировать:

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

jhilgert00
источник
но если мне не нужна «передача разных данных при отклонении из разных представлений, вызов разных методов при отклонении и т. д.», могу ли я сделать один небольшой вызов в представленном методе контроллера представления - [self dismissViewControllerAnimated: NO Завершение: nil]?
nikitahils
Разрешение докладчику отклонить представленное представление делает очевидным, что докладчик фактически готов и обрабатывает возврат на передний план: последовательность выполнения легко прослеживается, а ответственность за любое обновление пользовательского интерфейса неявно ясна.
Johan
3

Swift 3.0 // Быстро закрыть View Controller

self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
Pranit
источник
2

Цитата из Руководства по программированию контроллера View , «Как контроллеры представления представляют другие контроллеры представления».

Каждый контроллер представления в цепочке представленных контроллеров представления имеет указатели на другие объекты, окружающие его в цепочке. Другими словами, представленный контроллер представления, который представляет другой контроллер представления, имеет допустимые объекты как в свойствах PresentingViewController, так и в свойствах presentViewController. Вы можете использовать эти отношения для отслеживания цепочки контроллеров представления по мере необходимости. Например, если пользователь отменяет текущую операцию, вы можете удалить все объекты в цепочке, отклонив первый представленный контроллер представления. Отклонение контроллера представления закрывает не только этот контроллер представления, но и все представленные им контроллеры представления.

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

Хотя я лично предпочел бы использовать раскручивающиеся переходы, чем пытаться пройти назад по дереву контроллеров представления, о чем Apple говорит в этой главе, из которой взята цитата.

Свена
источник
2

Во-первых, это хороший подход к кодированию. Он удовлетворяет многим OOPпринципам, например, SRP, разделение интересов и т. Д.

Итак, контроллер представления, представляющий представление, должен его отклонить.

Например, компания по недвижимости, которая сдает дом в аренду, должна иметь право забрать его обратно.

Абдуррахман Мубин Али
источник
1

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

Скажем, ViewControllerA представляет ViewControllerB модально. Но поскольку вы, возможно, не написали код для ViewControllerA, вы не знаете о жизненном цикле ViewControllerA. Он может отклонить 5 секунд (скажем) после представления вашего контроллера представления ViewControllerB.

В этом случае, если вы просто использовали dismissViewController ViewControllerB для закрытия самого себя, вы бы оказались в неопределенном состоянии - возможно, не в результате сбоя или черного экрана, а в неопределенном состоянии с вашей точки зрения.

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

Mayur
источник
1

Swift

let rootViewController:UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!

        if (rootViewController.presentedViewController != nil) {
            rootViewController.dismiss(animated: true, completion: {
                //completion block.
            })
        }
Риши Чауразия
источник
0

Если вы используете модальный режим, используйте view dismiss.

[self dismissViewControllerAnimated:NO completion:nil];
ErasmoOliveira
источник
Как это отвечает на вопрос: «Почему первый вариант лучше? Почему Apple рекомендует его?»
jww
0

Это много чепухи. Делегирование - это нормально, когда оно необходимо, но если оно делает код более сложным - а это так, - тогда для этого должна быть причина.

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

Протоколы отлично подходят, когда они необходимы, но объектно-ориентированный дизайн никогда не предполагал ненужного взаимодействия модулей друг с другом.

Том Лав (со-разработчик Objective C) однажды заметил, что Objective C был «элегантным», «маленьким», «четким» и «четко определенным» (по сравнению с C ++). Ему легко сказать. Делегирование - это полезная функция, которая, кажется, использовалась чрезмерно «просто потому, что», и хотя мне нравится работать с языком, я опасаюсь, что я буду вынужден использовать ненужный синтаксис для усложнения вещей, чем они должны быть.

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

Вы можете закрыть окно супер просмотра

self.view.superview?.window?.close()

MR.Code
источник