UIViewController viewWillAppear не вызывается при добавлении как subView
У меня есть UIViewController
, который я загружаю из другого контроллера представления, а затем добавляю его представление к UIScrollView
.
self.statisticsController = [self.storyboard instantiateViewControllerWithIdentifier:@"StatisticsViewController"];
self.statisticsController.match = self.match;
[self.scrollView addSubview:self.statisticsController.view];
Я поставил точки останова в контроллере просмотра статистики и viewDidLoad
вызывается, но viewWillAppear
не работает.
Это потому, что я не нажимаю его на иерархию или что-то еще?
Ответы
Ответ 1
Вы должны добавить statisticsController
в качестве контроллера дочернего представления контроллера, представление которого вы добавляете.
self.statisticsController = [self.storyboard instantiateViewControllerWithIdentifier:@"StatisticsViewController"];
self.statisticsController.match = self.match;
[self.scrollView addSubview:self.statisticsController.view];
[self addChildViewController:self.statisticsController];
[self.statisticsController didMoveToParentViewController:self];
Я не уверен, что это вызовет вызов viewDidAppear
, но вы можете переопределить didMoveToParentViewController:
в дочернем контроллере, и это будет вызвано, поэтому вы можете поместить любой код, который вы положили бы в viewDidAppear
там.
Ответ 2
Я столкнулся с -viewWillAppear:
снова не вызванной проблемой. После гуглинга я приехал сюда. Я проверил несколько тестов и выяснил, что порядок вызова -addSubview
и -addChildViewController:
важен.
Случай 1. вызывает -viewWillAppear:
контроллера, но Случай 2, он не будет вызывать -viewWillAppear:
.
Случай 1:
controller?.willMoveToParentViewController(self)
// Call addSubview first
self.scrollView.addSubview(controller!.view)
self.addChildViewController(controller!)
controller!.didMoveToParentViewController(self)
Случай 2:
controller?.willMoveToParentViewController(self)
// Call adChildViewController first
self.addChildViewController(controller!)
self.scrollView.addSubview(controller!.view)
controller!.didMoveToParentViewController(self)
Ответ 3
По умолчанию обратные вызовы внешнего вида автоматически пересылаются детям. Он определяется с помощью свойства shouldAutomaticsForwardAppearanceMethods. Проверьте значение этого свойства, если оно НЕТ, и если ваш дочерний viewController должен отображаться прямо при появлении контейнера, вы должны уведомить дочерний процесс следующими способами в реализации жизненного цикла контроллера контейнера:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
for (UIViewController *child in self.childViewControllers) {
[child beginAppearanceTransition:YES animated:animated];
}
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.child endAppearanceTransition];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
for (UIViewController *child in self.childViewControllers) {
[child beginAppearanceTransition:NO animated:animated];
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.child endAppearanceTransition];
}
Настройка внешнего вида и поведения обратного вызова
Исправлена моя проблема! Надеюсь, это будет полезно.
Ответ 4
Как уже упоминалось в другом ответе, родительский контроллер представления может не вызывать viewWillAppear
и т.д., Если для параметра shouldAutomaticallyForwardAppearanceMethods
задано значение false
. UINavigationController
и UITabBarController
как известно, делают это. В этом случае вам нужно вызвать beginAppearanceTransition(_ isAppearing: Bool, animated: Bool)
на дочернем контроллере представления с isAppearing
установленным в true
когда представление появляется, и наоборот.
Вы должны размещать эти вызовы в соответствующих местах вашего кода, обычно, когда вы добавляете и удаляете дочерний контроллер представления.
Не забудьте вызвать endAppearanceTransition
на вашем дочернем контроллере представления, когда ваш пользовательский переход завершится, иначе viewDidAppear
и viewDidDisappear
не будут вызваны.
Ответ 5
В Apple (https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html) правильный порядок вызовов API для добавления контроллера детского представления:
[self addChildViewController:childVC];
[self.view addSubview:childVC.view];
[childVC didMoveToParentViewController:self];
Но у меня все еще была проблема, когда viewWillAppear в дочернем VC не вызывался спорадически. Моя проблема заключалась в том, что было состояние гонки, которое могло привести к тому, что код выше был выполнен, прежде чем viewDidAppear в контроллере представления контейнера был вызван. Обеспечение того, чтобы viewDidAppear уже был вызван (или отложил добавление дочернего VC до его появления), решил для меня.
Ответ 6
Предыдущие ответы верны, но в случае, если это кому-то поможет - если вы переопределите loadView
в дочернем контроллере представления, то не будет вызван ни один из других методов UIViewController.
Мне потребовалось некоторое время, чтобы понять, почему мой код не работает должным образом, пока я не понял, что случайно переопределил loadView
вместо viewDidLoad
.
Ответ 7
В моем случае я обнаружил, что неправильно переписал viewWillAppear:
метод в моем базовом классе UINavigationController
:
override func viewWillAppear(_ animated: Bool) {
super.viewWillDisappear(animated)
// other stuff
}
Обратите внимание, что вместо вызова super.viewWillAppear(animated)
я написал super.viewWillDisappear(animated)
.
Это привело к UIViewController
что все UIViewController
которые были внутри этого UINavigationController
не viewWillAppear:
метод.
Надеюсь, что это поможет кому-то по аналогичной проблеме.