iOS cómo detectar mediante progtwigción cuando aparece el controller de vista superior?

Supongamos que tengo una stack de controlleres de navigation con 2 controlleres de vista: VC2 está en la parte superior y VC1 está debajo. ¿Hay algún código que pueda include en el VC1 que detecte que el VC2 acaba de salir de la stack?

Como bash detectar la aparición de VC2 desde el código de VC1, parece que algo así como viewWillAppear o viewDidAppear no funcionará, ya que esos methods se disparan cada vez que se muestra VC1, incluso cuando se empuja por primera vez en la stack.

EDITAR: parece que no estaba muy claro con mi pregunta original. Esto es lo que bash hacer: determinar cuándo se muestra VC1 debido a que VC2 se ha salido de la parte superior de la stack. Esto es lo que NO trato de hacer: determine cuándo se muestra VC1 debido a que se lo empuja a la parte superior de la stack. Necesito una forma que detecte la primera acción pero NO la segunda acción.

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

iOS 5 introdujo dos nuevos methods para manejar exactamente este tipo de situaciones. Lo que está buscando es -[UIViewController isMovingToParentViewController] . De los documentos :

isMovingToParentViewController

Devuelve un valor boolean que indica que el controller de vista está en process de ser agregado a un elemento principal.

- (BOOL)isMovingToParentViewController

Valor de retorno
SÍ si el controller de vista está apareciendo porque se agregó como hijo de un controller de vista de contenedor, de lo contrario NO.

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

-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í: ¿te interesa el hecho de que VC2 en particular haya salido de la stack, o quieres que te notifiquen cada vez que se revela VC1 como resultado de cualquier intervención de controller? En el primer caso, la delegación es una solución mejor. Una reference débil y directa a VC1 también podría funcionar si nunca pretendes reutilizar VC2.

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

isMovingTo / FromParentViewController no funcionará para empujar y hacer estallar en una stack de controlleres de navigation.

Aquí hay una forma 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, el uso del delegado significaría que el comportamiento de los controlleres de vista estaría más estrechamente relacionado con el delegado que posee la stack de navigation, y quería una solución más independiente. Esto funciona.

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 de protocolos y delegates aquí .

También puede detectar en el controller de vista que se está haciendo estallar

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

Esto me ha funcionado

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

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

Si está tratando de detectar que VC1 está a punto de mostrarse, esta respuesta debería ayudarlo. Utilice UINavigationControllerDelegate .

Si está tratando de detectar que VC2 está a punto de ocultarse, simplemente usaría la vista viewWillDisappear: of VC2.

Puede agregar un observador para NSNotification específicamente JUST 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, en la vista de su VC2 desaparecerá, puede publicar una notificación:

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

sí, en VC1 puede comprobar si VC2 está o no aparece. UINavigationController hay una vista de método Controladores que devolverá la matriz de controlleres empujados, que se encuentran en la stack (medios que se han presionado). Así que itera a través del ciclo comparando la class. si VC2 está ahí, no tendrá otra opción. ¡Espero que esto te ayudará!

veloz 3

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

Recibí la misma situación pero con un caso de uso leve más específico. En mi caso, queríamos determinar si se muestra / muestra un VC1 cuando el usuario presiona el button de retroceso de VC2, donde VC2 se presiona en el control de navigation por VC1.

Entonces utilicé la ayuda de la respuesta de Snarshad a la medida según mis necesidades. Aquí está el código en la vista de VC1. viewDidAppear 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 appeanetworking") } }