Как 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:метод контроллера дочернего представления».

Кроме того , есть пример разработан здесь и примеры кода здесь .

Удачи

Timthetoolman
источник
17
Я понимаю, поэтому addChildViewControllerнужно уравновешивать didMoveToParentViewControllerи willMoveToParentViewControllerуравновешивать removeFromParentViewController. Это именно то, что я искал. Не знаю, как я это пропустил в документации.
Грегори Хигли
Почему нет? Почему вам не нужно вызывать willMoveToParentViewController, но нужно вызывать didMoveToParentViewController?
user4951
Потому что это то, что говорят документы. Apple явно считает, что нам не нужно знать.
7
Причина в анимации: предположим, вы создаете свой собственный контроллер навигации. В начале слайд-анимации нужно вызвать willMove, а в конце анимации нужно вызвать didMove. Теперь, когда вы вызываете addChild в начале анимации, он автоматически вызывает для вас willMove. Но он не может знать, когда анимация (если она есть) завершится, поэтому вам нужно вызвать didMove вручную в конце анимации (или сразу же, если анимация отсутствует).
Крис
2
А что касается анимации «выдвигается», например, дочерний элемент удаляется, вы должны вызвать «willMove» вручную в начале анимации, потому что в противном случае uikit не знал бы, когда вызывать «viewWillDisappear» дочернего виртуального канала. А в конце анимации, когда вы вызываете removeFromParentViewController, он может автоматически вызвать 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
Неванский король
источник
Похоже, что в противном случае, даже если кажется, что это работает, PresentingViewController не установлен для представленногоViewController.
Адриан
Документы говорят о вызове didMoveToParentViewController « сразу после вызова метода addChildViewController:», но не указывают, когда вы действительно добавляете дочернее подвид. Интересно, все ли ошибаются? Есть ли в некоторых документах Apple пример, по которому мы можем это проверить?
Роберт
Примечание: вы делаете необходимость вызова willMoveToParentViewControllerдо addChildViewControllerесли детали вы двигаетесь это пользовательский класс с переопределяются addChildViewController(если ваше переопределение не называет его внутренне)
bunkerdive