2010-03-01 16 views
14

Durante un tiempo he supuesto que viewDidUnload siempre se invoca cuando se desasigna un controlador. ¿Es esta una suposición correcta?Suelte en viewDidUnload and dealloc both?

He estado explorando algunas cosas raras, y he establecido un punto de interrupción en el controlador viewDidUnload y es dealloc. Parece que se llama a dealloc, pero nunca se llama al método viewDidUnload. Incluso agregué un self.view = nil a mi dealloc y todavía no parecía llamarlo.

¿Esto significa que los objetos de vista retenidos que he estado liberando en el método viewDidUnload también deben ser liberados en mi método dealloc para asegurarse de que realmente desaparezcan?

Sé que hay muchas otras preguntas sobre StackOverflow sobre viewDidUnload, pero ninguna aborda específicamente este problema sobre la duplicación de declaraciones de liberación entre los 2 métodos.


Un exmaple más concreta en un proyecto fresco en el SDK 3.1.2:

@implementation TestViewController 

@synthesize label; 

- (IBAction)push { 
    TestViewController *controller = [[[TestViewController alloc] initWithNibName:@"TestViewController" bundle:nil] autorelease]; 
    [self.navigationController pushViewController:controller animated:YES]; 
} 

- (void)viewDidUnload { 
    self.label = nil; 
    NSLog(@"viewDidUnload was called"); 
} 

- (void)dealloc { 
    [super dealloc]; 
    NSLog(@"label retain count: %i", [label retainCount]); 
} 

@end 

Mi delegado de la aplicación crea un controlador de navegación sencilla con uno de éstos, ya que es controlador de raíz. Cuando toco el botón vinculado a push 3 veces, y luego presiono el botón Atrás tres veces, se genera la siguiente salida.

ViewDidUnloadTest[2887:207] label retain count: 2 
ViewDidUnloadTest[2887:207] label retain count: 2 
ViewDidUnloadTest[2887:207] label retain count: 2 

Cuál es 2 más alto que yo pensaría que sería. Retenido una vez por la vista y una vez por el controlador. Pero después del dealloc, esperaba que la vista se hubiera ido al liberar mi etiqueta, y que el controlador se haya ido al viewDidUnload y lo haya liberado. Aunque puede haber un autorelease arrojando el conteo en este punto.

Pero al menos está claro que viewDidUnload no está recibiendo llamados en absoluto, lo contrario a esta respuesta aquí: Are viewDidUnload and dealloc always called when tearing down a UIViewController?

Quizá simplemente debería llamar [self viewDidUnload] en todos mis métodos dealloc en los controladores? Peor de lo que puede suceder es que establecí una propiedad en cero dos veces, ¿verdad?

Respuesta

20

A menos que necesite interrumpir un ciclo de retención, debería generalmente liberar objetos solo en su método dealloc. viewDidUnload es una excepción; se invoca en situaciones de poca memoria y se debe utilizar para liberar todo lo que pueda.

Si necesita liberarlos en cualquier otro lugar, establezca siempre la referencia en nil después del release. Eso protegerá su aplicación de volar más tarde (probablemente en dealloc).

Tenga en cuenta que la documentación indica explícitamente que la propiedad de vista ya será nula cuando se llame a viewDidUnload.

+0

Así que usted está diciendo "Sí, necesita liberar las propiedades retenidas en su' dealloc' incluso si las libera y anula en su método 'viewDidUnload'"? –

+3

Exactamente; viewDidUnload es para situaciones de poca memoria y dealloc es para limpieza. Los dos son ortogonales. – bbum

+1

¡Este es un punto muy confuso que proviene de los ejemplos! La mayoría de los ejemplos muestran cosas que se configuran como nulas en viewDidUnload.Lo que no puede explicar es que después de que algo se establece en cero, no se puede liberar y esperar que se desasigne. Sin tomar nota de esto, terminarás con pérdidas de memoria por todos lados. Gracias por tu útil publicación. – jocull

Cuestiones relacionadas