container - ios uiviewcontroller lifecycle
UIViewController viewWillAppear no se llama cuando se agrega como subView (7)
Tengo un UIViewController
que estoy cargando desde otro controlador de vista y luego agrego su vista a un UIScrollView
.
self.statisticsController = [self.storyboard instantiateViewControllerWithIdentifier:@"StatisticsViewController"];
self.statisticsController.match = self.match;
[self.scrollView addSubview:self.statisticsController.view];
He puesto puntos de interrupción en el controlador de vista de estadísticas y se está llamando a viewWillAppear
pero no a viewWillAppear
.
¿Es porque no estoy empujando a la jerarquía o algo así?
Como se mencionó en otra respuesta, es posible que el controlador de vista principal no llame a viewWillAppear
etc., cuando shouldAutomaticallyForwardAppearanceMethods
se establece en false
. Se sabe que UINavigationController
y UITabBarController
hacen eso. En este caso, debe llamar a beginAppearanceTransition(_ isAppearing: Bool, animated: Bool)
en el controlador de vista secundario con isAppearing
establecido en true
cuando aparezca la vista y viceversa.
Debe realizar estas llamadas en los lugares apropiados de su código, normalmente cuando agrega y quita el controlador de vista secundario.
No olvide llamar a endAppearanceTransition
en su controlador de vista secundario cuando endAppearanceTransition
su transición personalizada, de lo contrario no se llama a viewDidAppear
y viewDidDisappear
.
Debe agregar statisticsController
como un controlador de vista secundario del controlador a la que lo está agregando.
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];
No estoy seguro de que esto haga que se viewDidAppear
a viewDidAppear
, pero puede anular didMoveToParentViewController:
en el controlador secundario, y se llamará, por lo que puede poner cualquier código que haya puesto en viewDidAppear
allí.
En mi caso, encontré que reescribió incorrectamente un método viewWillAppear:
en mi clase base UINavigationController
:
override func viewWillAppear(_ animated: Bool) {
super.viewWillDisappear(animated)
// other stuff
}
Tenga en cuenta que, en lugar de llamar a super.viewWillAppear(animated)
escribí super.viewWillDisappear(animated)
.
Eso provocó que todos los UIViewController
que estaban dentro de este UINavigationController
no viewWillAppear:
método viewWillAppear:
.
Espero que ayude a alguien en un tema similar.
Las respuestas anteriores son correctas, pero en caso de que ayude a alguien, si reemplaza loadView
en el controlador de vista secundaria, no se llamará a ninguno de los otros métodos de UIViewController.
Tardé un poco en darme cuenta de por qué mi código no se ejecutaba correctamente, hasta que me di cuenta de que había anulado accidentalmente loadView
lugar de viewDidLoad
.
Me encuentro con -viewWillAppear:
no se llama problema de nuevo. Después de googlear, vine aquí. Hice algunas pruebas y descubrí que el orden de -addSubview
de -addSubview
y -addChildViewController:
es importante.
El caso 1. activará -viewWillAppear:
del controlador, pero el caso 2, NO llamará -viewWillAppear:
Caso 1:
controller?.willMoveToParentViewController(self)
// Call addSubview first
self.scrollView.addSubview(controller!.view)
self.addChildViewController(controller!)
controller!.didMoveToParentViewController(self)
Caso 2:
controller?.willMoveToParentViewController(self)
// Call adChildViewController first
self.addChildViewController(controller!)
self.scrollView.addSubview(controller!.view)
controller!.didMoveToParentViewController(self)
Por Apple ( https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/ImplementingaContainerViewController.html ), el orden correcto de las llamadas API para agregar un controlador de vista secundario es:
[self addChildViewController:childVC];
[self.view addSubview:childVC.view];
[childVC didMoveToParentViewController:self];
Pero todavía tenía el problema de que viewWillAppear in the Child VC no se llamaba esporádicamente. Mi problema era que había una condición de carrera que podía hacer que el código anterior se ejecutara antes de que se llamara viewDidAppear en el controlador de vista de contenedor. Asegurarme de que viewDidAppear ya se había llamado (o aplazar la adición de la VC secundaria hasta que lo hubo) lo resolvió por mí.
Por defecto, las devoluciones de llamadas de apariencia se reenvían automáticamente a los hijos. Se determina con la propiedad shouldAutomaticallyForwardAppearanceMethods . Verifique el valor de esta propiedad, si es NO y si su hijo viewController debe aparecer justo en la apariencia del contenedor, debe notificar al niño con los siguientes métodos en la implementación del ciclo de vida del controlador del contenedor:
- (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];
}
Personalización del comportamiento de devolución de llamada de apariencia y rotación
¡Arreglado mi problema! Espero que sea de ayuda.