Я просто впервые погружаюсь в разработку для iOS, и первое, что мне пришлось сделать, это реализовать настраиваемый контроллер представления контейнера (позвольте назвать его), SideBarViewController
который меняет местами, какой из нескольких возможных контроллеров представления дочерних элементов он отображается почти так же, как стандартный контроллер панели вкладок . (Это в значительной степени контроллер панели вкладок, но с скрытым боковым меню вместо панели вкладок.)
Согласно инструкциям в документации Apple, я вызываю addChildViewController
каждый раз, когда добавляю дочерний ViewController в свой контейнер. Мой код для замены текущего контроллера дочернего представления отображается SideBarViewController
следующим образом:
- (void)showViewController:(UIViewController *)newViewController {
UIViewController* oldViewController = [self.childViewControllers
objectAtIndex:0];
[oldViewController removeFromParentViewController];
[oldViewController.view removeFromSuperview];
newViewController.view.frame = CGRectMake(
0, 0, self.view.frame.size.width, self.view.frame.size.height
);
[self addChildViewController: newViewController];
[self.view addSubview: newViewController.view];
}
Затем я начал пытаться понять, что addChildViewController
здесь происходит, и понял, что понятия не имею. Кроме втыкания нового ViewController
в .childViewControllers
массив, похоже, ни на что не влияет. Действия и выходы из представления дочернего контроллера в дочерний контроллер, который я установил на раскадровке, по-прежнему работают нормально, даже если я никогда не вызываю addChildViewController
, и я не могу представить, на что еще это могло повлиять.
В самом деле, если я перепишу свой код, чтобы он не звонил addChildViewController
, а вместо этого выглядел бы так ...
- (void)showViewController:(UIViewController *)newViewController {
// Get the current child from a member variable of `SideBarViewController`
UIViewController* oldViewController = currentChildViewController;
[oldViewController.view removeFromSuperview];
newViewController.view.frame = CGRectMake(
0, 0, self.view.frame.size.width, self.view.frame.size.height
);
[self.view addSubview: newViewController.view];
currentChildViewController = newViewController;
}
... тогда мое приложение по-прежнему работает отлично, насколько я могу судить!
Документация Apple не проливает много света на то addChildViewController
, что это такое и почему мы должны это называть. Полный объем соответствующего описания того, что делает метод или почему он должен использоваться в его разделе в UIViewController
Справочнике классов , в настоящее время:
Добавляет заданный контроллер представления как дочерний. ... Этот метод предназначен только для вызова реализацией настраиваемого контроллера представления контейнера. Если вы переопределите этот метод, вы должны вызвать super в своей реализации.
Также есть этот абзац ранее на той же странице:
Контроллер представления контейнера должен связать контроллер дочернего представления с собой перед добавлением корневого представления дочернего элемента в иерархию представлений. Это позволяет iOS правильно маршрутизировать события на контроллеры дочерних представлений и представления, которыми управляют эти контроллеры. Аналогично, после того, как он удаляет корневое представление дочернего элемента из его иерархии представлений, он должен отключить этот контроллер дочернего представления от самого себя. Чтобы создать или разрушить эти ассоциации, ваш контейнер вызывает определенные методы, определенные базовым классом. Эти методы не предназначены для вызова клиентами вашего контейнерного класса; они должны использоваться только реализацией вашего контейнера, чтобы обеспечить ожидаемое поведение сдерживания.
Вот основные методы, которые вам может понадобиться вызвать:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
но он не дает никаких подсказок относительно того, какие «события» или «ожидаемое поведение сдерживания», о котором идет речь, или почему (или даже когда) вызов этих методов «необходим».
Все примеры настраиваемых контроллеров представления контейнеров в разделе «Настраиваемые контроллеры представления контейнеров» документации Apple вызывают этот метод, поэтому я предполагаю, что он служит какой-то важной цели, помимо простого добавления дочернего ViewController в массив, но я не могу понять что это за цель. Что делает этот метод и почему я должен его называть?
источник
Ответы:
Меня тоже интересовал этот вопрос. Я смотрел сеанс 102 видео WWDC 2011, и мистер View Controller Брюс Д. Нило сказал следующее:
Кажется, что призыв к
addChildViewController:
очень мало делает. Побочные эффекты звонка - важная часть. Они исходят из отношенийparentViewController
иchildViewControllers
отношений. Вот некоторые из известных мне побочных эффектов:transitionFromViewController:toViewController:…
если у обоих VC должен быть один и тот же родительский элемент.navigationController
,tabBarController
и т.д. свойстваисточник
Я думаю, что пример стоит тысячи слов.
Я работал над приложением библиотеки и хотел показать красивый вид блокнота, который появляется, когда пользователь хочет добавить заметку.
Попробовав несколько решений, я изобрел собственное решение для отображения блокнота. Поэтому, когда я хочу показать блокнот, я создаю новый экземпляр
NotepadViewController
и добавляю его корневое представление в качестве подпредставления к основному представлению. Все идет нормально.Потом я заметил, что изображение блокнота частично скрыто под клавиатурой в ландшафтном режиме.
Итак, я хотел изменить изображение блокнота и сдвинуть его вверх. И для этого я написал правильный код в
willAnimateRotationToInterfaceOrientation:duration:
методе, но когда я запустил приложение, ничего не произошло! И после отладки я заметил, что ни один изUIViewController
методов вращения на самом деле не вызываетсяNotepadViewController
. Вызываются только эти методы в главном контроллере представления.Чтобы решить эту проблему, мне нужно было вызвать все методы
NotepadViewController
вручную, когда они вызываются в главном контроллере представления. Это скоро усложнит ситуацию и создаст дополнительную зависимость между несвязанными компонентами в приложении.Это было в прошлом, до появления концепции дочерних контроллеров представления. Но теперь вам нужно только перейти
addChildViewController
к контроллеру основного представления, и все будет работать так, как ожидалось, без дополнительной ручной работы.Изменить: есть две категории событий, которые перенаправляются дочерним контроллерам представления:
1- Способы появления:
2- Методы вращения:
Вы также можете контролировать, какие категории событий вы хотите пересылать автоматически, переопределив
shouldAutomaticallyForwardRotationMethods
иshouldAutomaticallyForwardAppearanceMethods
.источник
addChildViewController
на родительский контроллер.-[UIViewController addChildViewController:]
добавляет только переданный в представление контроллер в массив viewController, на который viewController (родительский элемент) хочет сохранить ссылку. Фактически вы должны сами добавить эти представления viewController на экран, добавив их в качестве подвидов другого представления (например, представления parentViewController). В Interface Builder также есть удобный объект для использования childrenViewControllers в раскадровках.Раньше, чтобы сохранять ссылки на другие viewControllers, представления которых вы использовали, вам приходилось вручную ссылаться на них в @properties. Наличие встроенного свойства, такого как
childViewControllers
и, следовательно,parentViewController
является удобным способом управления такими взаимодействиями и создания составных контроллеров представления, таких как UISplitViewController, которые вы найдете в приложениях для iPad.Более того, childrenViewControllers также автоматически получает все системные события, которые получает родитель: -viewWillAppear, -viewWillDisappear и т. Д. Раньше вы должны были вызывать эти методы вручную для своих «childrenViewControllers».
Вот и все.
источник
iOS "system events"
ничего не дает; похоже, это не тот термин, который использует Apple?