2009-04-30 8 views
7

alguna parte he leído que - en cuanto a las advertencias de poca memoria y renunciar a una vista no visible gracias a todas sus subvistas (= toda una punta, creo), usted debe hacer lo siguiente:¿Por qué debería escribir [anView release], anView = nil; en lugar de [anView release] ;?

-(void)dealloc { 
    [anView release], anView = nil; 
    [someImageView release], someImageView = nil; 

    [super dealloc]; 
} 

en lugar de

-(void)dealloc { 
    [anView release]; 
    [someImageView release]; 

    [super dealloc]; 
} 

¿Cuál es la razón para poner a tierra esos punteros a nil (= "no object"), después de que llame al lanzamiento? Déjame adivinar: Algún otro método podría haber retenido la vista por alguna razón (¿alguien puede dar algún ejemplo de cuándo podría suceder esto?), Entonces sucede lo que ocurre en la memoria de recuperación de documentos, y liberas una vista de plumín + que no está visible (es decir, en una aplicación multiview). Tan pronto como el usuario quiera volver a ver esa vista, cargará rápidamente la punta de nuevo y luego: ¡Cargará todas las vistas, conectará las tomas y BANG! Las otras vistas retenidas cuelgan ahora sin ningún puntero en algún lugar solitario en el panel de memoria, lo que provoca una pérdida de memoria abundante y gruesa hasta que la aplicación se cuelga.

¿Derecha/Incorrecta?

Respuesta

1

en lugar de hacer el lanzamiento expicit y ajuste a cero, si sus descriptores de acceso tienen propiedades asociadas con ellos YOC y haga lo siguiente como un método más concisa:

- (void) dealloc 
{ 
    self.retainedProperty1 = nil; 
    self.retainedProperty2 = nil; 
    self.copiedProperty = nil; 
    self.assignedProperty = nil; 
} 

esta manera usted puede tener código que tiene menos repetición ya que el código sintetizado se ocupará de sus lanzamientos por usted.

Editar: Debo señalar que sus propiedades no pueden ser de sólo lectura o de lo contrario se producen errores de compilación, por razones obvias :)

+5

No. Esto es * explícitamente * prohibido por Apple, y una buena manera de causar un bloqueo en algunas circunstancias. Ver http://stackoverflow.com/questions/192721/why-shouldnt-i-use-obective-c-2-0-accessors-in-init-dealloc –

+0

Ese enlace trae a colación un buen punto, pero ¿sigue siendo un mala idea si solo la usa para las propiedades readwrite que están totalmente sintetizadas? (lo que significa que no declaras la sintetización para una propiedad y aún anulas el getter o setter) – Kevlar

+0

Probablemente esté bien, por ahora, con propiedades totalmente sintetizadas. Pero Apple no garantiza que esté permitido y recomienda no hacerlo, por lo que podría romperse en cualquier SDK futuro. –

14

El principio es más general que UIView. de hecho, es más general que el método Objective-C/Cocoa -release. Es válido también con las funciones de memoria C malloc()/free().

Cuando ya no necesite un objeto o una zona de memoria, primero la libera/libera. Luego, para asegurarse de no volver a utilizarlo, borre los medios para acceder a este objeto o zona de memoria asignando un nil a un objeto o un NULL en un puntero de memoria.

+4

1. El punto principal es que eliminar referencias a un puntero nulo aborta la ejecución inmediatamente, mientras que la referenciación de un puntero a la memoria ya liberada puede 'funcionar' durante un tiempo y genera errores desagradables. – zoul

+0

Gracias. Me pregunto por qué vemos ese patrón tan raramente en ejemplos de código. Nunca lo he visto en el código de Apple. Pero me parece razonable hacer eso, y supongo que no dolerá de todos modos. – Thanks

+0

El código de muestra rara vez sigue las mejores prácticas. el objetivo de la mayoría del código de muestra es demostrar un principio, api o método lo más concisamente posible. – m4rkk

11

Some other method could have -retain'ed the view for some reason

A menos que estés invocando dealloc a sí mismo, sólo se llama cuando la cuenta de retención se convierte en cero.

Tenga en cuenta que en Objective-C enviar un mensaje a un nil "objeto" es (a menudo) perfectamente bien. Si lo hace, no hace que su programa se detenga, pero el mensaje simplemente se ignora. Sin embargo, no puede enviar un mensaje a un objeto liberado, lo que produciría un bloqueo.

Por lo tanto, la siguiente sería darle un error:

[anView release]; 
[anView doSomething]; 

Pero, esto es, de hecho, bien:

[anView release]; 
anView = nil; 
[anView doSomething]; 

Es una cuestión de gustos, pero por lo anterior, es posible que en De hecho, prefieren bloquear su programa, en lugar de preguntarse por qué no se ejecuta algo.

Véase también Sending Messages to nil de Apple Introduction to The Objective-C 2.0 Programming Language.

2

utilizo este patrón mucho:

- (void) showHelp: (id) sender 
{ 
    if (helpController == nil) 
    { 
     helpController = [[HelpController alloc] initWithNibName: @"Help" bundle: [NSBundle mainBundle]]; 
    } 
    [self presentModalViewController: helpController animated: YES];  
} 
- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview 
    // Release anything that's not essential, such as cached data 
    [helpController release]; 
    helpController = nil; 
} 

prácticamente en todas partes que asigno un viewcontroller que es modal, o de otra manera "temporal". De esta manera, se cuelga si lo necesito de nuevo, pero se va si la memoria baja.

4

Se llama al método -dealloc cuando se libera el objeto y no se ejecutarán otros métodos en el objeto después. Por lo tanto, establecer cualquier variable de instancia en nil no tiene ningún efecto fuera de ese objeto.

Si estaba liberando un objeto (sin usar un setter) en otro lugar de la clase, sería importante establecer la variable de instancia en cero para evitar que el código en otro lugar envíe un mensaje a esa dirección.

+1

"no se ejecutarán otros métodos en el objeto después de" - +1 para obtener una explicación clara de lo obvio. ¡Gracias! (En cuanto a "importante establecer la variable de instancia en cero para evitar que el código en otro lugar envíe un mensaje a esa dirección", me pregunto por qué es preferible ignorar un mensaje no deseado antes que recibir un mensaje de error ...) – Arjan

+3

Porque todos los programas contienen errores, incluso los bien probados lanzados al cliente. Los tipos de errores generados por el envío de mensajes a nulo (básicamente un no-op) suelen ser menos graves que los errores generados al enviar un mensaje a un objeto liberado. El primero generalmente da como resultado errores de lógica en los que el programa no funciona exactamente como se esperaba, lo último resultará en un bloqueo. Durante el desarrollo, los bloqueos son bienvenidos, ya que permiten encontrar el error, no así para los productos lanzados. – m4rkk

Cuestiones relacionadas