example bar ios uinavigationcontroller stack

bar - ¿iOS cómo detectar mediante programación cuándo aparece el controlador de vista superior?



root view controller navigation controller (10)

Supongamos que tengo una pila de controlador de navegación con 2 controladores de vista: VC2 está en la parte superior y VC1 está debajo. ¿Hay algún código que pueda incluir en VC1 que detecte que el VC2 acaba de salir de la pila?

Como intento detectar el estallido de VC2 desde dentro del código para VC1, parece que algo como viewWillAppear o viewDidAppear no funcionará, porque esos métodos se disparan cada vez que se muestra VC1, incluso cuando se empuja por primera vez en la pila.

EDITAR: parece que no estaba muy claro con mi pregunta original. Esto es lo que estoy tratando de hacer: determinar cuándo se está mostrando VC1 debido a que VC2 se quitó de la parte superior de la pila. Esto es lo que NO trato de hacer: determinar cuándo VC1 se muestra debido a que se ha colocado en la parte superior de la pila. Necesito alguna forma que detecte la primera acción pero NO la segunda acción.

Nota: No me preocupa particularmente el VC2, puede ser cualquier cantidad de otros VCs que salgan de la pila, lo que sí me importa es cuando VC1 se convierta en la parte superior de la pila nuevamente debido a que otros VC comienzan a aparecer en la pila. parte superior.


¿Qué estás tratando específicamente de hacer?

Si está tratando de detectar que el VC1 está a punto de mostrarse, this respuesta debería ayudarlo. Use UINavigationControllerDelegate .

Si está intentando detectar que el VC2 está a punto de ocultarse, simplemente usaría viewWillDisappear: de VC2.


Esto me funciona

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey]; if (![[self.navigationController viewControllers] containsObject:fromViewController] && !self.presentedViewController) { //Something is being popped and we are being revealed }


Puede agregar un observador para NSNotification específicamente SOLO para su VC2.

// pasing the "VC2" here will tell the notification to only listen for notification from // VC2 rather than every single other objects [[NSNotitificationCenter defaultCenter] addObserver:self selector:@selector(doSomething:) object:VC2];

Ahora que la vista de su VC2 desaparecerá, puede publicar una notificación:

-(void)viewWillDisappear { [[NSNotificationCenter defaultCenter] postNotificationNamed:@"notif_dismissingVC2" object:nil]; }


Sí, en VC1 puede verificar si VC2 aparece o no. UINavigationController hay un método viewControllers que devolverá la matriz de Controladores empujados, que están en la pila (es decir, que se han insertado).

Entonces itera a través del ciclo comparando clase. Si VC2 está allí, tendrá coincidencia, de lo contrario no.


También puede detectar en el controlador de vista que se está reventado

- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if ([self isMovingFromParentViewController]) { .... } }


Tengo la misma situación, pero con un caso de uso ligeramente más específico. En mi caso, queríamos determinar si apareció o apareció un VC1 cuando el usuario toca el botón Atrás del VC2 donde se presiona VC2 en el control de navegación sobre el VC1.

Así que utilicé la ayuda de la respuesta de snarshad a medida según mi necesidad. Aquí está el código en viewDidAppear de VC1 en swift 3 .

// VC1: ParentViewController // VC2: ChildViewController override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if let transitionCoordinator = navigationController?.transitionCoordinator, let fromVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.from), let toVC = transitionCoordinator.viewController(forKey: UITransitionContextViewControllerKey.to), fromVC is ChildViewController, toVC is ParentViewController { print("Back button pressed on ChildViewController, and as a result ParentViewController appeared") } }


Una forma de abordar esto sería declarar un protocolo de delegado para VC2 algo como esto:

en VC1.h

@interface VC1 : UIViewController <VC2Delegate> { ... }

en VC1.m

-(void)showVC2 { VC2 *vc2 = [[VC2 alloc] init]; vc2.delegate = self; [self.navigationController pushViewController:vc2 animated:YES]; } -(void)VC2DidPop { // Do whatever in response to VC2 being popped off the nav controller }

en VC2.h

@protocol VC2Delegate <NSObject> -(void)VC2DidPop; @end @interface VC2 : UIViewController { id<VC2Delegate> delegate; } @property (nonatomic, assign) id delegate; ... @end

VC2.m

-(void)viewDidUnload { [super viewDidUnload]; [self.delegate VC2DidPop]; }

Hay un buen artículo sobre los conceptos básicos y los delegados here .


isMovingTo / FromParentViewController no funcionará para empujar y hacer estallar en una pila de controlador de navegación.

Aquí hay una manera confiable de hacerlo (sin usar el delegado), pero probablemente solo sea iOS 7+.

UIViewController *fromViewController = [[[self navigationController] transitionCoordinator] viewControllerForKey:UITransitionContextFromViewControllerKey]; if ([[self.navigationController viewControllers] containsObject:fromViewController]) { //we''re being pushed onto the nav controller stack. Make sure to fetch data. } else { //Something is being popped and we are being revealed }

En mi caso, usar el delegado significaría tener el comportamiento de los controladores de visualización más estrechamente unido con el delegado que posee la pila de navegación, y yo quería una solución más independiente. Esto funciona.


veloz 3

override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) if self.isMovingToParentViewController { print("View is moving to ParentViewControll") } }


iOS 5 introdujo dos nuevos métodos para manejar exactamente este tipo de situación. Lo que estás buscando es -[UIViewController isMovingToParentViewController] . De los docs :

isMovingToParentViewController

Devuelve un valor booleano que indica que el controlador de vista está en proceso de agregarse a un elemento primario.

- (BOOL)isMovingToParentViewController

Valor de retorno
SÍ si el controlador de vista está apareciendo porque se agregó como elemento secundario de un controlador de vista de contenedor; de lo contrario, NO.

Discusión
Este método devuelve SÍ solo cuando se llama desde dentro de los siguientes métodos:

-viewWillAppear:
-viewDidAppear:

En su caso, podría implementar -viewWillAppear: así:

- (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if (self.isMovingToParentViewController == NO) { // we''re already on the navigation stack // another controller must have been popped off } }

EDITAR: Hay una sutil diferencia semántica a considerar aquí: ¿le interesa el hecho de que VC2, en particular, saltó de la pila, o desea que se le notifique cada vez que se revela VC1 como resultado de la aparición de cualquier controlador? En el primer caso, la delegación es una mejor solución. Una referencia débil y directa al VC1 también podría funcionar si nunca intentas reutilizar el VC2.

EDIT 2: Hice el ejemplo más explícito al invertir la lógica y no regresar temprano.