Як працює View Controller Containment в iOS 5?


108

У WWDC 2011 Session 102, Apple представила View Controller Стримування, який є можливість створення користувацьких подань контролера контейнерів, аналогічно UITabBarController, UINavigationControllerтощо.

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

Сценарій 1: Перехід від батьківського до нового контролера подання батьків

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Чи повинні відбуватися перші два рядки в заданому порядку, або вони можуть бути відмінені?

Сценарій 2: Перехід від батьківського контролера перегляду до жодного батьківського контролера подання

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

Чи потрібно також телефонувати [vc didMoveToParentViewController:nil]? Приклади сесії 102 цього не робили в цьому сценарії, але я не знаю, був це упущення чи ні.

Сценарій 3: Перехід від одного контролера батьківського перегляду до іншого

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

// In the old parent
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

// In the new parent
[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];

Запитання

Головне моє запитання таке: чи взагалі має працювати таким чином функція захисту контролера перегляду? Чи правильні наведені вище механіки?

Чи потрібно телефонувати willMoveToParentViewControllerперед тим, як дзвонити addChildViewController? Мені це здається логічним наказом, але чи це суворо необхідно?

Чи потрібно телефонувати didMoveToParentViewController:nilпісля дзвінка removeFromParentViewController?

Відповіді:


72

Ці UIViewControllerдокументи є досить ясно , коли і якщо не називати willMove/ didMoveметодів. Перегляньте документацію "Впровадження контролера перегляду контейнерів" .

Документи кажуть, що якщо ви не переосмислюєте addChildViewController, вам не доведеться викликати willMoveToParentViewController:метод. Однак вам потрібно викликати didMoveToParentViewController:метод після завершення переходу. "Точно також відповідальність контролера перегляду контейнерів є викликом willMoveToParentViewController:методу перед викликом removeFromParentViewControllerметоду. removeFromParentViewControllerМетод викликає didMoveToParentViewController:метод контролера дочірнього перегляду."

Крім того , є приклад розроблений тут і приклади коду тут .

Щасти


17
Я бачу, тому addChildViewControllerслід врівноважуватись didMoveToParentViewControllerі willMoveToParentViewControllerбути врівноваженим removeFromParentViewController. Це саме те, що я шукав. Не впевнений, як я пропустив це в документах.
Gregory Higley

Чому ні? Чому вам не потрібно зателефонувати willMoveToParentViewController, а щоб зателефонувати didMoveToParentViewController?
user4951

Тому що так говорять документи. Яблуко, очевидно, відчуває, що нам не потрібно знати.

7
Причиною є анімація: Скажіть, ви створюєте власний контролер навігації. На початку анімації слайдів потрібно викликати "willMove", а в кінці анімації потрібно викликати "didMove". Тепер, коли ви викликаєте "addChild" на початку анімації, він автоматично викликає "willMove" для вас. Але він не може знати, коли закінчується анімація (якщо така є), тому вам доведеться викликати "didMove" вручну в кінці анімації (або негайно без анімації).
Кріс

2
А що стосується анімації "висунути", наприклад, дитина видаляється, ви повинні викликати "willMove" вручну на початку анімації, тому що uikit інакше не знатиме, коли викликати "viewWillDisappear" вашої дитини VC. І наприкінці анімації, коли ви викликаєте deleteFromParentViewController, він може автоматично зателефонувати "didMove".
Кріс

23

Ця частина неправильна:

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Згідно з документами:

Коли ваш спеціальний контейнер викликає метод addChildViewController:, він автоматично викликає метод willMoveToParentViewController: метод контролера перегляду, який потрібно додати як дочірнє перед його додаванням.

Тож вам не потрібен [vc willMoveToParentViewController:self]дзвінок. Це робиться автоматично під час дзвінка [self addChildViewController:vc]. Ось знову зразок коду:

[self addChildViewController:vc];
// [vc willMoveToParentViewController:self] called automatically
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Для видалення контролерів перегляду:

Метод removeFromParentViewController автоматично викликає метод didMoveToParentViewController: метод контролера дочірнього перегляду після його видалення.

Імовірно, це дзвінок [oldVC didMoveToParentViewController:nil].

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
// [vc didMoveToParentViewController:nil] called automatically

виявляється, що якщо це робиться інакше, навіть якщо, здається, це працює, представленняViewController не встановлено на представленомуViewController.
Адріан

Документи кажуть, що зателефонували didMoveToParentViewController " відразу після виклику методу addChildViewController::", він не визначає, коли ви фактично додаєте дочірнє підпогляд. Цікаво, чи всі помилялися. Чи є приклад у деяких документах Apple, з якими ми можемо це перевірити?
Роберт

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