2011-03-14 14 views
49

He estado buscando una solución en Internet. No hay nada que pueda encontrar. Entonces: Estoy usando un UINavigationController. Estoy presionando dos UIViewControllers en él. En el segundo empujó ViewController Estoy ejecutando este código:iOS: comportamiento inesperado de popViewController

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error { 
NSLog([error localizedDescription]); 
[self.navigationController popViewControllerAnimated:YES]; } 

Lo esperado a suceder sería que el último empujado ViewController desaparece. En esta aplicación, estoy haciendo esto en pocos lugares y funciona bien en todas partes, espero en este mismo ViewController. Lo que ocurre es que solo el botón Atrás se apaga (animado) pero todo lo demás permanece en la pantalla. En la consola de salida dos cosas se imprimen cuando se ejecuta esta línea:

2011-03-14 16: 32: 44.580 TheAppXY [18518: 207] anidado animación pop puede resultar en corrompido barra de navegación

2011-03-14 16: 32: 53.507 TheAppXY [18518: 207] Finalizando una transición de navegación en un estado inesperado . El árbol de subvista de barra de navegación puede dañarse.

Dos mensajes de error No pude encontrar CUALQUIER información. Estoy usando XCode 4 y iOS SDK 4.3. Quizás alguien pueda ayudarme con este problema.

+1

Creo que lo descubrí solo. Creo que es porque trato de abrir el controlador de visualización demasiado pronto.Si el geocodificador reverso entregó una dirección (que se inició en ViewDidLoad) y falló, la vista no apareció todavía, por lo que el estallido animado no funciona bien, obviamente. Ahora implementé el inicio del geocodificador inverso en ViewDidAppear y todo parece funcionar bien. Error de principiante más o menos. Pero me pregunto si no hay información para encontrar al respecto – Christoph

+0

Recientemente, he enfrentado el mismo problema. La razón fue: "Estaba tratando de mostrar el controlador de vista dos veces por error. puede verificar este bloqueo estableciendo puntos de interrupción en los controles de vista push y pop –

Respuesta

28

Puede obtener esto cada vez que intente pop antes del viewDidAppear. Si configura una bandera, simplemente marque esa bandera en viewDidAppear, no tendrá problemas.

+0

Este parece ser el enfoque más seguro – Dmytro

50

me encontré con una situación similar en mi código y el mensaje dice:

anidada animación empuje puede resultar en la barra de navegación dañado

Terminando una transición de navegación en un estado inesperado. El árbol de la subvista de la barra de navegación> puede dañarse.

Mi descubrimiento de este problema fue que estaba presionando 2 controladores de vista uno detrás de otro en rápida sucesión y ambos estaban animados.

En su caso, parece que puede estar sacando múltiples controladores de vista con animación uno después del otro.

Por lo tanto, aunque una vista está en proceso de animación, no debería iniciar la animación en otra vista.

También encontré que si desactivaba la animación en una vista, el mensaje de error desaparecía.

En mi caso, era un problema con la lógica de flujo ya que no tenía la intención de empujar 2 controladores de vista uno después del otro. Una estaba siendo empujada dentro de la lógica de la caja del interruptor y otra después de su final.

Espero que esto ayude a alguien.

+10

La clave aquí para mí fue: "... y ambos estaban animados". ¡Gracias! –

+0

¿Tiene alguna recomendación para manejar situaciones en las que le gustaría hacer esto? Por ejemplo, veo esto mucho cuando presiono un controlador de vista en la pila, y luego muestro un UIAlertView. Todavía quiero mostrarles a los dos, preferiría que la Vista se insertara en la pila, y luego aparecería la vista de alerta sin tener que implementar un montón de métodos de delegado. – dsingleton

+3

Gracias cuando cambié a este 'Animated: YES' a' Animated: NO' y llamé a mi método pop en 'viewDidAppear', resolvió el problema –

3

he tenido este problema, también, y esto es lo que estaba causando la mía:

  1. En RootViewController, estoy usando varios objetos UISegmentedControl para determinar cuál de los muchos puntos de vista a la carga siguiente.
  2. En esa vista (sub/2da), estaba volviendo (al usar el botón "Atrás") de nuevo a RootViewController.
  3. En RootViewController, estaba manejando viewWillAppear para "restablecer" cada uno de mis objetos UISegmentedControl a un SelectedSegmentIndex de -1 (lo que significa que ningún segmento se ve "presionado").
  4. Ese "reinicio" activó cada uno de mis objetos UISegmentedControl para activar sus IBActions asociadas (y separadas).
  5. Como no manejaba para una "selección" de -1, tenía varios métodos disparando al mismo tiempo, todos intentando impulsar una vista diferente.

Mi solución? Reforcé mis declaraciones if ... then y rescaté la ejecución de cualquier código en mis IBActions de control de UISegmented cuando selectedSegmentIndex == -1.

Todavía no estoy seguro de por qué recibí errores de animación "pop" y no errores de "inserción", pero al menos resolví mi error y lo solucioné.

Espero que esto ayude a alguien más!

12

He creado un reemplazo directo para UINavigationController que colocará en cola las animaciones y evitará este problema por completo.

Grab desde BufferedNavigationController

+0

Hola Andrew, ¿sigues apoyando la clase anterior? Por alguna razón, no funciona para mí, como puede ver aquí: http://stackoverflow.com/questions/16634337/right-to-left-push-animation-results-in-corrupted-navigation-bar – Segev

+0

Vea también mi UINavigationControllerWithQueue Responda a continuación, para una alternativa – MarkWPiper

0

sí, por desgracia, Apple no sincronizar las animaciones de UINavigationController. La solución de Andrew es excelente, pero si usted no desea para cubrir toda su funcionalidad, hay una solución simple, anular estos dos métodos:

// navigation end event 

- (void) navigationController : (UINavigationController*) pNavigationController 
      didShowViewController : (UIViewController*  ) pController 
      animated    : (BOOL     ) pAnimated 
{ 

    if ([ waitingList count ] > 0) [ waitingList removeObjectAtIndex : 0 ]; 
    if ([ waitingList count ] > 0) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ]; 

} 


- (void) pushViewController : (UIViewController*) pController 
      animated   : (BOOL) pAnimated 
{ 

    [ waitingList addObject : pController ]; 
    if ([ waitingList count ] == 1) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ]; 

} 

y crear una variable de instancia NSMutableArray llamada waitingList, y ya está.

+0

Tomé esta idea y la generalicé para que también funcione con popViewController * en la respuesta siguiente, UINavigationControllerWithQueue – MarkWPiper

0

Este problema me sucede cuando uso storyboards. He cometido un error: Tengo un UIButton con una acción para realizarSegueWithIdentifier. Así que vinculo la transición de pulsación con Button con el otro ViewController, por lo que se produce este problema.

Resolver: Enlace la acción del botón en UIButton y vincule la transición de pulsación entre dos ViewControllers.

0

La combinación de MilGra y las respuestas de Andrew me dieron algo que funciona de manera confiable y es un reemplazo más simple de UINavigationController.

Esto mejora la respuesta de MilGra para que funcione con empujes y saltos, pero es más simple que el BufferedNavigationController de Andrew. (Utilizando BufferedNavigationController ocasionalmente recibía transiciones que nunca se completarían y solo mostraban una pantalla negra.)

Todo esto parece no ser necesario en iOS8, pero todavía era necesario para mí en iOS7.

@implementation UINavigationControllerWithQueue { 
    NSMutableArray *waitingList; 
} 

-(void) viewDidLoad { 
    [super viewDidLoad]; 
    self.delegate = self; // NOTE: delegate must be self! 
    waitingList = [[NSMutableArray alloc] init]; 
} 

# pragma mark - Overrides 

-(void) pushViewController: (UIViewController*) controller 
        animated: (BOOL) animated { 
    [self queueTransition:^{ [super pushViewController:controller animated:animated]; }]; 
} 

- (UIViewController *)popViewControllerAnimated:(BOOL)animated { 
    UIViewController *result = [self.viewControllers lastObject]; 
    [self queueTransition:^{ [super popViewControllerAnimated:animated]; }]; 
    return result; 
} 

- (NSArray*)popToRootViewControllerAnimated:(BOOL)animated { 
    NSArray* results = [self.viewControllers copy]; 
    [self queueTransition:^{ [super popToRootViewControllerAnimated:animated]; }]; 
    return results; 
} 

# pragma mark - UINavigationControllerDelegate 

-(void) navigationController: (UINavigationController*) navigationController 
     didShowViewController: (UIViewController*) controller 
        animated: (BOOL) animated { 
    [self dequeTransition]; 
} 

# pragma mark - Private Methods 

-(void) queueTransition:(void (^)()) transition { 
    [waitingList addObject:transition]; 
    if (waitingList.count == 1) { 
     transition(); 
    } 
} 

-(void) dequeTransition { 
    if (waitingList.count > 0) { 
     [waitingList removeObjectAtIndex:0]; 
    } 
    if (waitingList.count > 0) { 
     void (^transition)(void) = [waitingList objectAtIndex:0]; 
     if (transition) { 
      transition(); 
     } 
    } 
} 

@end 
+0

Funcionó muy bien en el simulador, pero no de manera confiable en el dispositivo, por lo que al final no es un enfoque recomendado . – MarkWPiper

Cuestiones relacionadas