2012-02-04 18 views
18

Cuando el usuario cambia a otro programa y luego regresa nuevamente, la vista del programa original será reemplazada por una nueva vista desde otro programa. Entonces, cuando el usuario vuelve al programa original, ¿se llamaría a viewDidLoad por segunda vez?¿Con qué frecuencia se llama a viewDidLoad?

Pregunto esto porque si este es el caso, entonces el código de inicialización colocado dentro de viewDidLoad se ejecutará cada vez que el usuario cambie la pantalla hacia adelante y hacia atrás. Y esto podría dar lugar a reseting vistas y desatar las obras inacabadas del usuario ...

+0

Gracias por el comentario. – Stanley

+4

El comentario no es correcto.Se invoca cada vez que se carga la vista de su controlador de vista, no solo la primera vez. –

+0

Gracias por la corrección ... – Stanley

Respuesta

26

No ver la inicialización del controlador en viewDidLoad. Este es un error común.

Para la materia que sólo debe suceder una vez cuando se carga el controlador de vista, hacerlo en el método init del controlador, así:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)bundleOrNil 
{ 
    if ((self = [super initWithNibName:nibNameOrNil bundle:bundleOrNil])) 
    { 
     //do your initialisation here 
    } 
    return self; 
} 

El método initWithNibName:bundle: se llama antes se carga la vista desde la plumín, y solo se llama una vez en la vida útil del controlador de vista.

La vista del controlador se puede cargar y descargar varias veces durante la vida útil del controlador y se llamará viewDidLoad en todo momento. Se puede descargar cuando no está en la pantalla, generalmente si la memoria es baja.

Si configura cosas en viewDidLoad (por ejemplo, agregar subvistas mediante programación) siempre debe volver a desactivarlas en viewDidUnload.

Piense en viewDidLoad y como siendo como el init/dealloc para la propiedad de vista del controlador de vista. Para las cosas que se relacionan con las vistas, créelo y suéltelo en esos métodos. Para las cosas que se relacionan con el controlador mismo, créelo y suéltelo en initWithNibName y dealloc.

UPDATE: En iOS 6 y más tarde, viewDidUnload nunca es llamado más (a menos que la vista se establece explícitamente a cero en el código), y así viewDidLoad sólo se suelen llamarse una vez en la vida de un controlador de vista . Esto hace que los consejos anteriores sean menos críticos, pero sigue siendo la mejor práctica, y sigue siendo necesario si necesita admitir iOS 5 y versiones anteriores.

ACTUALIZACIÓN 2: Si va a cargar el controlador de vista de un guión (que ahora es la práctica recomendada) en lugar de crear mediante programación a continuación, no se llamará initWithNibName:bundle:. Use initWithCoder: o awakeFromNib para inicializar su controlador en su lugar.

+0

Gracias por su respuesta detallada ... – Stanley

+0

Usted dijo "Este método se llama antes de que la vista se cargue desde el plumín", ¿qué es "Esto" se refiere a "initWithNibName" o "viewDidLoad"? – Stanley

+0

Disculpas, lo he aclarado. –

3

De the docs:

Este método se llama después de que el controlador de vista ha cargado sus puntos de vista asociados en la memoria.

Por lo tanto, se invoca cada vez que el controlador de vista tiene sus vistas cargadas en la memoria. Esta podría ser la primera vez que la vista es cargado y nunca más, o cada vez que la vista se hace visible si su vista constantemente lo descarga (viewDidUnload debido a las limitaciones de memoria, etc.)

+0

Gracias por su respuesta ... - – Stanley

4

-viewDidLoad se llamará una vez cada vez que el controlador de vista necesita cargar su jerarquía de vista Obviamente, eso sucederá la primera vez que el controlador acceda a su vista. Si el controlador de vista descarga posteriormente su vista, se volverá a llamar al -viewDidLoad la próxima vez que se cargue la vista. Un controlador de vista no descargará su vista solo porque la vista está oculta, pero podría hacerlo si la memoria comienza a agotarse.

Un controlador de vista debe conocer el estado de sus vistas y ser capaz de configurarlas según sea necesario en su método -viewDidLoad. Las vistas no se deben usar para almacenar estados: no se debe perder irrevocablemente nada solo porque la vista está descargada.

+1

Gracias por su respuesta detallada ... – Stanley

+0

Acerca de "Un controlador de vista debe conocer el estado de sus vistas", desea preguntarle a esta "capacidad para mantener el estado" es la responsabilidad de nuestra costumbre código o está incorporado en la biblioteca de Cocoa? – Stanley

+1

No está incorporado. El punto es que su controlador de vista no debe contar con vistas para mantener el estado. Por ejemplo, si tiene un control deslizante en su vista, su controlador de vista debe recordar el valor del control deslizante cada vez que cambie. De esta forma, si la vista se descarga y luego se carga de nuevo, el controlador de vista puede restablecer el control deslizante a ese valor guardado en -viewDidLoad. – Caleb

5

Entonces, cuando el usuario vuelve al programa original, ¿se llamaría viewDidLoad por segunda vez?

(de arriba es de la op)

En esos casos hay dos métodos que se llamará:

- (void)applicationWillEnterForeground:(UIApplication *)application; 

volver a abrir una aplicación en segundo plano (de administrador de tareas o desde el trampolín de nuevo)
desbloqueo del dispositivo que está bloqueado cuando la aplicación está activa.

- (void)applicationDidBecomeActive:(UIApplication *)application 

después de las llamadas telefónicas
notificación centro de despido
administrador de tareas despido (doble toque botón de inicio & a tocar dos veces)

+0

Gracias por su respuesta detallada ... – Stanley

17

@ Nick Lockwood proporciona una excelente información, pero hay algunas cosas más a tener en cuenta .

Primero, initWithNibName:bundle: no se invoca si el controlador de vista se crea una instancia desde un archivo de punta o guión gráfico. En ese caso, se llaman en su lugar initWithCoder: y awakeFromNib. Esta situación solía ser algo poco común en iOS, pero con la adición de guiones gráficos ahora es mucho más común que los controladores de vista eludan initWithNibName:bundle:.

recomiendo poner el código de inicialización no UI en un método separado (que llamo mío setup) y lo llaman tanto initWithNibName:bundle: y awakeFromNib. Pero solo hago esto si es importante que esa inicialización solo se ejecute una vez. De lo contrario, lo puse en viewWillAppear: para que sea lo más perezoso posible. En segundo lugar, no debe hacer nada que haga referencia a self.view en init... o awakeFromNib. Nunca debe hacer referencia al self.view hasta llamar al viewDidLoad (de lo contrario, forzará que el archivo nib se cargue antes de lo necesario). Las cosas relacionadas con la interfaz de usuario deben ir en viewDidLoad si están relacionadas con la configuración de las vistas, o viewWillAppear: si están relacionadas con la configuración de las vistas (es decir, cargarlas con datos).

Así que la forma en que generalmente se fijan estas cosas:

@implementation 

- (void)setup { 
    // Non-UI initialization goes here. It will only ever be called once. 
} 

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle { 
    if ((self = [super initWithNibName:nibName bundle:bundle])) { 
    [self setup]; 
    } 

    return self; 
} 

- (void)awakeFromNib { 
    [self setup]; 
} 

- (void)viewDidLoad { 
    // Any UI-related configuration goes here. It may be called multiple times, 
    // but each time it is called, `self.view` will be freshly loaded from the nib 
    // file. 
} 

- (void)viewDidUnload { 
    [super viewDidUnload]; 
    // Set all IBOutlets to `nil` here. 
    // Drop any lazy-load data that you didn't drop in viewWillDisappear: 
} 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    // Most data loading should go here to make sure the view matches the model 
    // every time it's put on the screen. This is also a good place to observe 
    // notifications and KVO, and to setup timers. 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 
    // Unregister from notifications and KVO here (balancing viewWillAppear:). 
    // Stop timers. 
    // This is a good place to tidy things up, free memory, save things to 
    // the model, etc. 
} 

- (void)dealloc { 
    // standard release stuff if non-ARC 
    [[NSNotificationCenter defaultCenter] removeObvserver:self]; // If you observed anything 
    // Stop timers. 
    // Don't unregister KVO here. Observe and remove KVO in viewWill(Dis)appear. 
} 

@end 
+0

Gracias por la respuesta detallada ... – Stanley

+1

Realmente debería agregar una muestra de viewDidUnload a su excelente ejemplo. – Till

+0

@Till, gracias por la nota. Me olvidé de incluir viewDidUnload. Fijo. –

Cuestiones relacionadas