viewWillDisappear: determine si el controlador de vista se está desplegando o si muestra un controlador de subvista
-
08-07-2019 - |
Pregunta
Estoy luchando por encontrar una buena solución a este problema. En el método -viewWillDisappear:
de un controlador de vista, necesito encontrar una manera de determinar si es porque un controlador de vista está siendo empujado a la pila del controlador de navegación, o si es porque el controlador de vista está desapareciendo porque ha sido reventado.
En este momento estoy configurando banderas como isShowingChildViewController
pero se está volviendo bastante complicado. La única forma en que creo que puedo detectarlo es en el método -dealloc
.
Solución
Puede usar lo siguiente.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSArray *viewControllers = self.navigationController.viewControllers;
if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
// View is disappearing because a new view controller was pushed onto the stack
NSLog(@"New view controller was pushed");
} else if ([viewControllers indexOfObject:self] == NSNotFound) {
// View is disappearing because it was popped from the stack
NSLog(@"View controller was popped");
}
}
Esto es posible, por supuesto, porque la pila del controlador de vista de UINavigationController (expuesta a través de la propiedad viewControllers) se ha actualizado cuando se llama a viewWillDisappear.
Otros consejos
Creo que la forma más fácil es:
- (void)viewWillDisappear:(BOOL)animated
{
if ([self isMovingFromParentViewController])
{
NSLog(@"View controller was popped");
}
else
{
NSLog(@"New view controller was pushed");
}
[super viewWillDisappear:animated];
}
Swift:
override func viewWillDisappear(animated: Bool)
{
if isMovingFromParentViewController
{
print("View controller was popped")
}
else
{
print("New view controller was pushed")
}
super.viewWillDisappear(animated)
}
De la documentación de Apple en UIViewController.h:
" Estos cuatro métodos se pueden usar en la apariencia de un controlador de vista devoluciones de llamada para determinar si se presenta, se descarta o se agrega o eliminado como un controlador de vista secundario. Por ejemplo, un controlador de vista puede verificar si está desapareciendo porque se descartó o apareció preguntándose en su viewWillDisappear: método marcando el expresión ([self isBeingDismissed] || [self isMovingFromParentViewController]). "
- (BOOL) isBeingPresented NS_AVAILABLE_IOS (5_0);
- (BOOL) isBeingDismissed NS_AVAILABLE_IOS (5_0);
- (BOOL) isMovingToParentViewController NS_AVAILABLE_IOS (5_0);
- (BOOL) isMovingFromParentViewController NS_AVAILABLE_IOS (5_0);
Entonces, sí, la única forma documentada de hacerlo es la siguiente:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if ([self isBeingDismissed] || [self isMovingFromParentViewController]) {
}
}
Versión Swift 3:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed || self.isMovingFromParentViewController {
}
}
Si solo desea saber si su vista está apareciendo, acabo de descubrir que self.navigationController
es nil
en viewDidDisappear
, cuando Se elimina de la pila de controladores. Esa es una prueba alternativa simple.
(Esto lo descubro después de probar todo tipo de otras contorsiones. Me sorprende que no haya un protocolo de controlador de navegación para registrar un controlador de vista para recibir notificaciones en los pops. No puede usar UINavigationControllerDelegate
porque eso en realidad hace un trabajo de visualización real.)
Swift 4
override func viewWillDisappear(_ animated: Bool)
{
super.viewWillDisappear(animated)
if self.isMovingFromParent
{
//View Controller Popped
}
else
{
//New view controller pushed
}
}
En Swift:
override func viewWillDisappear(animated: Bool) {
if let navigationController = self.navigationController {
if !contains(navigationController.viewControllers as! Array<UIViewController>, self) {
}
}
super.viewWillDisappear(animated)
}
Creo que la documentación de Apple sobre esto es difícil de entender. Esta extensión ayuda a ver los estados en cada navegación.
extension UIViewController {
public func printTransitionStates() {
print("isBeingPresented=\(isBeingPresented)")
print("isBeingDismissed=\(isBeingDismissed)")
print("isMovingToParentViewController=\(isMovingToParentViewController)")
print("isMovingFromParentViewController=\(isMovingFromParentViewController)")
}
}
Esta pregunta es bastante antigua, pero la vi por accidente, así que quiero publicar las mejores prácticas (afaik)
puedes simplemente hacer
if([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
// view controller popped
}
Esto se aplica a iOS7 , no tengo idea si se aplica a otros. Por lo que sé, en viewDidDisappear
la vista ya se ha abierto. Lo que significa que cuando consulta self.navigationController.viewControllers
obtendrá un nil
. Así que solo verifique si eso es nulo.
TL; DR
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if (self.navigationController.viewControllers == nil) {
// It has been popped!
NSLog(@"Popped and Gone");
}
}
Los segmentos pueden ser una forma muy efectiva de manejar este problema en iOS 6+. Si le ha dado al segmento particular un identificador en Interface Builder, puede verificarlo en prepareForSegue
.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"LoginSegue"]) {
NSLog(@"Push");
// Do something specific here, or set a BOOL indicating
// a push has occurred that will be checked later
}
}
Supongo que quiere decir que su vista se está moviendo hacia abajo en la pila del controlador de navegación al presionar una nueva vista cuando dice empujado a la pila. Sugeriría usar el método viewDidUnload
para agregar una instrucción NSLog
para escribir algo en la consola para que pueda ver lo que está sucediendo, es posible que desee agregar un NSLog
para viewWillDissappeer
.
Aquí hay una categoría para lograr lo mismo que la respuesta de sbrocket:
Header:
#import <UIKit/UIKit.h>
@interface UIViewController (isBeingPopped)
- (BOOL) isBeingPopped;
@end
Fuente :
#import "UIViewController+isBeingPopped.h"
@implementation UIViewController (isBeingPopped)
- (BOOL) isBeingPopped {
NSArray *viewControllers = self.navigationController.viewControllers;
if (viewControllers.count > 1 && [viewControllers objectAtIndex:viewControllers.count-2] == self) {
return NO;
} else if ([viewControllers indexOfObject:self] == NSNotFound) {
return YES;
}
return NO;
}
@end