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


116

У мене є теоретичне питання. Тепер я читаю посібник із ViewController від Apple .

Вони написали:

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

Але я не можу пояснити, чому мені потрібно створити протокол у представленому VC та додати змінну делегата, створити метод делегата для подання VC для відхилення представленого VC, а не простий виклик у представленому методі контролера перегляду

[self dismissViewControllerAnimated:NO completion:nil]?

Чому перший вибір кращий? Чому Apple рекомендує це?

Відповіді:


122

Я думаю, що Apple трохи прикриває свої спини для потенційно хитрої частини API.

  [self dismissViewControllerAnimated:NO completion:nil]

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

Можливо, вони зіткнулися з безліччю поганого коду людьми, які не дуже розуміють, як це складено разом, звідси і їх обережність.

Але звичайно, якщо все, що вам потрібно зробити, це відмовитись від справи, йдіть далі.

Мій власний підхід є компромісом, принаймні, це нагадує мені, що відбувається:

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

[Швидкий]

  self.presentingViewController?.dismiss(animated: false, completion:nil)

26
Слід зазначити, що користуватися presentingViewControllerздебільшого марно, оскільки це стосуватиметься, UINavigationControllerякщо selfвбудований в одне ціле. У цьому випадку, ви не зможете отримати presentingViewControllerна всіх. Тим не менш, [self dismissViewControllerAnimated:completion]все ще працює в цьому випадку. Моя пропозиція буде продовжувати використовувати це, поки Apple не виправить це.
пам’ятки

4
Мені подобається, що ця відповідь залишається абсолютно актуальною через 3 роки.
user1021430

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 попросить представник-контролер подати рішення про звільнення.

Так працює представлений контролер подання, щоб викликати його на себе. Ось повний приклад.

Делегати

Питання ОП полягало у складності використання делегатів для відхилення погляду.

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


50

Це для повторного використання контролера перегляду.

Ваш контролер перегляду не повинен перейматися, подається він як модальний, натиснутий на навігаційний контролер чи інше. Якщо ваш контролер перегляду відхиляє себе, то ви припускаєте, що він представлений модально. Ви не зможете натиснути цей контролер перегляду на навігаційний контролер.

Реалізуючи протокол, ви дозволяєте батьківському контролеру перегляду вирішувати, яким чином він повинен бути представлений / висунутий та відхилений / вискочений.



6

На мій досвід, це стане в нагоді, коли вам потрібно відмовитися від будь-якого якого потрібного ViewController і виконати різні завдання для кожного контролера перегляду, який його відхиляє. Будь-який viewController, який приймає протокол, може відхилити подання по-своєму. (ipad vs iphone або передача різних даних при відхиленні від різних поглядів, виклик різних методів при звільненні тощо).

Редагувати:

Отже, для уточнення, якщо все, що ви хочете зробити, це відхилити перегляд, я не бачу необхідності налаштовувати протокол делегування. Якщо вам потрібно буде робити різні речі після того, як ви відпустите їх від різних представників контролерів подання, це був би найкращий спосіб скористатися делегатом.


але якщо мені не потрібно "передавати різні дані при звільненні з різних поглядів, виклику різних методів при звільненні тощо", чи можу я зробити один невеликий дзвінок у представленому методі контролера подання - [самовідпустітьViewControllerAnimated: НЕ завершення: нуль]?
nikitahils

Дозволяючи ведучому відмовитися від представленого виду, стає очевидним, що презентатор насправді готовий і справляється з поверненням на перший план: послідовність виконання легко дотримуватися, а відповідальність за будь-яке оновлення інтерфейсу явно чітка.
Йоган

2

Цитата з Посібника з програмування перегляду контролера , "Як представлення контролерів представляє інші контролери перегляду".

Кожен контролер виду у ланцюзі представлених контролерів подання має покажчики на інші об'єкти, що оточують його у ланцюзі. Іншими словами, представлений контролер подання, який представляє інший контролер перегляду, має дійсні об'єкти як у своїх властивостях представленняViewController, так і в представленихViewController властивостях. Ви можете використовувати ці зв’язки для простеження через ланцюг контролерів перегляду, якщо це необхідно. Наприклад, якщо користувач скасує поточну операцію, ви можете видалити всі об'єкти з ланцюга, відхиливши перший представлений контролер подання. Відхилення контролера перегляду відхиляє не тільки цей контролер перегляду, але й будь-які представлені ним контролери подання.

Отже, з одного боку, це приємний врівноважений дизайн, хороша роз'єднаність і т. Д. ... Але з іншого боку це дуже практично, тому що ви можете швидко повернутися до певної точки навігації.

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


2

Один момент полягає в тому, що це хороший підхід до кодування. Він задовольняє багато OOPпринципів, наприклад, SRP, розділення проблем тощо.

Отже, контролер перегляду, що представляє погляд, повинен бути тим, хто його відхиляє.

Мовляв, компанія з нерухомості, яка надає будинок в оренду, повинна мати повноваження взяти його назад.


2

Swift 3.0 // Відхилити контролер перегляду швидко

self.navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)

1

Окрім відповіді Майкла Енрікеса, я можу придумати ще одну причину, чому це може бути хорошим способом захистити себе від невизначеного стану:

Скажімо, ViewControllerA представляє ViewControllerB модально. Але, оскільки ви, можливо, не написали код для ViewControllerA, ви не знаєте про життєвий цикл ViewControllerA. Він може відхилити 5 секунд (скажімо) після того, як представить ваш контролер перегляду ViewControllerB.

У цьому випадку, якби ви просто використовували dismissViewControllerвід ViewControllerB для відхилення себе, ви опинилися б у невизначеному стані - можливо, це не збій чи чорний екран, а невизначений стан з вашої точки зору.

Якщо замість цього ви використовували шаблон делегата, ви б знали про стан ViewControllerB і можете запрограмувати такий випадок, як описаний я.


1

Швидкий

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

        if (rootViewController.presentedViewController != nil) {
            rootViewController.dismiss(animated: true, completion: {
                //completion block.
            })
        }

0

Якщо ви використовуєте модальне використання, вигляд відхилити.

[self dismissViewControllerAnimated:NO completion:nil];

Як це відповідає на питання: "Чому перший вибір краще? Чому Apple рекомендує його?"
jww

0

Це багато балонів. Делегація прекрасна, коли вона потрібна, але якщо вона робить код складнішим - і це так - тоді в цьому має бути причина.

Я впевнений, що Apple має свої причини. Але зрозуміліше і стисліше просто запропонувати представленому КВ зробити звільнення, якщо немає справжньої причини зробити інше, і ніхто сьогодні не представив жодної, яку я бачу.

Протоколи є чудовими, коли вони потрібні, але об'єктно-орієнтована конструкція ніколи не полягала в тому, щоб модулі спілкувалися без потреби.

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


Це може врятувати вам якийсь код спочатку, але ваш підхід спричинить вам багато болів в голові, коли база вашого коду зростатиме. Ви повинні розуміти об'єктно-орієнтовані принципи, такі як розділення проблем, інакше ви можете також кодувати всю свою програму в один великий файл.
Вернер Альтевишер

-2

Ви можете закрити вікно суперпрогляду

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.