viewWillDisappear: determine si el controlador de vista se está desplegando o si muestra un controlador de subvista

StackOverflow https://stackoverflow.com/questions/1816614

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 .

¿Fue útil?

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top