2010-07-07 16 views
9

Tengo un controlador de navegación. Una de las vistas agrega subvistas personalizadas en su viewDidAppear:. Noté que la primera vez que navego a una instancia de este controlador de vista después de iniciar la aplicación, invoca dos veces viewDidAppear:. Si saco esta vista de la pila y navego hacia ella de nuevo, viewDidAppear: invoca solo una vez por aparición. Todas las apariciones posteriores invocan viewDidAppear: una vez.viewDidAppear llamó dos veces en la misma instancia, pero solo la primera vez que esta clase se carga forma NIB

El problema para mí es que la primera vez que llego a esta vista, termino con el doble de subvistas. Resuelvo este problema mediante la introducción de una variable de marcador o algo así, pero me gustaría entender qué está sucediendo y cómo puedo obtener dos invocaciones en estas circunstancias.

Respuesta

14

Nunca se debe confiar en que -viewWillAppear:/-viewDidAppear: se denomine adecuadamente equilibrado con las variantes de desaparecer. Si bien los controladores de vista del sistema harán lo mejor posible para mantener siempre las llamadas de forma adecuada, no sé si alguna vez lo garantizarán y, ciertamente, al usar controladores de vista personalizados, se pueden encontrar situaciones en las que se pueden llamar varias veces.

En resumen, sus métodos -viewWillAppear:/-viewDidAppear: deben ser idempotentes, lo que significa que si se llama a -viewDidAppear: dos veces seguidas en su controlador, debería comportarse correctamente. Si desea cargar vistas personalizadas, puede hacerlo en el -viewDidLoad en su lugar y luego simplemente poner en pantalla (si no lo están) en -viewDidAppear:.

También podría poner un punto de interrupción en su método -viewDidAppear: para ver por qué se llama dos veces la primera vez que aparece.

+0

Tengo un punto de interrupción en 'viewDidAppear:'. ¿Cómo puede responder la pregunta por qué? – iter

+0

Mire la traza de pila para descubrir por qué el sistema llama a este método. Si la traza inversa es diferente para ambas llamadas, puede usar esto para intentar averiguar qué está pasando. Sin embargo, esto puede o no ser útil, dependiendo precisamente de lo que está contenido en la traza inversa. –

+0

Las pilas se ven idénticas, de ahí mi sorpresa por su sugerencia. Mi solución es refactorizar el código para poder llamar el código en 'viewDidAppear:' indirectamente desde 'viewDidLoad:', y así evitar todo el problema. Estoy aceptando tu respuesta, aunque la doble invocación sigue siendo un misterio para mí. – iter

1

quizás invoque viewDidAppear en viewDidLoad (o alguna otra cosa está sucediendo allí), ya que se invoca solo una vez durante la carga de la vista desde la memoria. Coincide, es invocado dos veces solo la primera vez.

+0

Eso fue lo primero que pensé. Pero no, no estoy haciendo eso. Y si configuro un punto de interrupción para ver la invocación 'viewDidAppear:', ninguno de mis propios métodos aparece en él. – iter

0

Definitivamente debe proporcionar más información.

¿Es este el controlador de vista raíz?
¿Quizás inicie el controlador de navegación con este controlador de vista raíz y luego lo vuelva a presionar al controlador de navegación?

+0

Una idea interesante, pero no, no la presiono dos veces. I 'NSLog (@"% @ ", [[self navigationController] viewControllers]);' from 'viewDidAppear' y veo una instancia de mi vista en la parte superior de la vista raíz. – iter

+0

¿Quizás tiene 2 controles de navegación por error? –

0

Otra solución que puede haber sido su causa subyacente: asegúrese de no presentar ningún nuevo controlador de vista dentro de su método viewWillAppear:.

estaba llamando:

[appDel.window.rootViewController presentViewController:login animated:YES completion:nil]; 

desde dentro viewWillAppear y ver mi originario viewDidAppear: método de VC llamado dos veces sucesivamente con la misma traza de la pila como usted menciona.Y no hay ninguna llamada intermediario para viewDidDisappear:

Moving presentViewController: a la originaria método de VC viewDidAppear: aclaró el tema de doble llamada, y lo que ahora el flujo es:

  1. original viewDidAppear: llama
    • llamada presentViewController aquí
  2. Original viewDidDisappear: llamado
  3. Nueva vista se presenta y ya no me da una advertencia sobre "unbalanced VC display"

fija con la ayuda de esta respuesta: https://stackoverflow.com/a/13315360/1143123 al tratar de resolver "Unbalanced calls to begin/end appearance transitions for ..."

-1

es un problema tan molesto, uno pensaría que funciona una sola vez pero luego descubrí que esto está causando caos ... Esto se aplica a todos 3 (ViewDidAppear, ViewDidLoad y ViewWillAppear), estoy obteniendo esto al integrarme con un terminal de pago; una vez que termina de llamar a la API, la ventana se vuelve a cargar cuando ya está en pantalla y toda su memoria todavía está allí (no retenida).

lo resolví de la siguiente manera a todas las rutinas mencionadas anteriormente, a continuación es una muestra de una de ellas:

BOOL viewDidLoadProcessed = false; 

-(void)viewDidLoad:(BOOL)animated 
{ 
    if (!viewDidLoadProcessed) 
    { 
     viewDidLoadProcessed = YES; 
     . 
     . 
     . 
     ... do stuff here... 
     . 
     . 
    } 
} 

Repetir lo anterior para todos los otros dos, esto impide que se ejecute dos veces. ¡Esto nunca ocurrió antes de que Steve Jobs muriera!

Saludos cordiales Heider Sati

1

Si usted tiene una línea como esta en su AppDelegate

window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 

asegurarse de que usted no tiene un "archivo principal punta nombre base" propiedad en su plist configurado en "Window.xib" o lo que sea que se llame su plumilla de ventana personalizada. Si lo hace, eliminar esa fila de su plist y asegurarse de que algo así como

yourRootVC = [[UIViewController alloc] init]; 
[window setRootViewController:yourRootVC]; 

en su AppDelegate después de crear instancias de la ventana. En la mayoría de los casos, también puede eliminar Window.xib de forma segura.

1

Adición [super viewDidAppear:animated]; trabajó para mí:

//Called twice 
- (void)viewDidAppear:(BOOL)animated{ 

} 

//Called once 
- (void)viewDidAppear:(BOOL)animated{ 
    [super viewDidAppear:animated]; 
} 
+1

Al registrar esto, el súper no deja de cargar dos veces. –

Cuestiones relacionadas