2008-09-15 18 views
37

Si tengo algo así como un UILabel vinculado a un archivo xib, ¿necesito liberarlo en dealloc de mi vista? La razón por la que pregunto es porque no la asigno, ¿qué me hace pensar que tampoco necesito liberarla? por ejemplo (en la cabecera):¿Debo liberar recursos xib?

IBOutlet UILabel *lblExample; 

en la implementación:

.... 
[lblExample setText:@"whatever"]; 
.... 

-(void)dealloc{ 
    [lblExample release];//????????? 
} 

Respuesta

35

Si usted sigue lo que ahora se considera como la mejor práctica, que debe propiedades de salida de la liberación, ya que debería haberlos retenido en el conjunto de acceso:

@interface MyController : MySuperclass { 
    Control *uiElement; 
} 
@property (nonatomic, retain) IBOutlet Control *uiElement; 
@end 


@implementation MyController 

@synthesize uiElement; 

- (void)dealloc { 
    [uiElement release]; 
    [super dealloc]; 
} 
@end 

La ventaja de este enfoque es que se hace que la semántica de administración de memoria sea explícita y clara, y funciona de manera consistente en todas las plataformas para todos los archivos nib.

Nota: los siguientes comentarios se aplican solo a iOS antes de 3.0. Con 3.0 y posterior, en su lugar, simplemente debe anular los valores de propiedad en viewDidUnload.

Una consideración aquí, sin embargo, es cuando el controlador podría disponer de su interfaz de usuario y volver a cargar de forma dinámica en la demanda (por ejemplo, si tiene un controlador de vista que carga una vista desde un archivo de punta, pero a petición - decir bajo presión de memoria: lo libera, con la expectativa de que pueda volver a cargarse si la vista es necesaria de nuevo). En esta situación, quiere asegurarse de que cuando se deseche la vista principal, también renuncie a la propiedad de otros puntos de venta para que también puedan desasignarse. Para UIViewController, se puede hacer frente a este problema reemplazando setView: de la siguiente manera:

- (void)setView:(UIView *)newView { 
    if (newView == nil) { 
     self.uiElement = nil; 
    } 
    [super setView:aView]; 
} 

Desafortunadamente esto da lugar a un problema aún más.Debido a que UIViewController implementa actualmente su método dealloc utilizando el método de acceso setView: (en lugar de simplemente liberar la variable directamente), se llamará en dealloc, así como en respuesta a una advertencia de memoria ... Esto provocará un bloqueo en dealloc.

El remedio consiste en asegurar que las variables de salida también están listos para nil en dealloc:

- (void)dealloc { 
    // release outlets and set variables to nil 
    [anOutlet release], anOutlet = nil; 
    [super dealloc]; 
} 
+0

Si tenemos una propiedad de retención, no podríamos simplificar esto simplemente diciendo self.uiElement = nil; en todos los lugares que queremos liberar, ya que es una propiedad retener en realidad debería lanzarla correctamente y establecerla en cero sin problemas, una de las ventajas de retener propiedades. –

+1

Normalmente harías 'self.uiElement = nil;' en 'viewDidUnload' no en' setView: '. Y sería más claro simplemente llamar 'self.anOutlet = nil;' en el dealloc. –

+2

No debe llamar a self.anOutlet = nil; en el trato. Es una mala práctica llamar a los usuarios en dealloc. – tobyc

0
+1

@Soeren: Ya he leído ese artículo y entiendo su contenido. Mi pregunta fue en relación con los objetos instanciados en un IB xib, que no cubre. Por ejemplo: nunca creo ni asigno la etiqueta, la magia IB hace todo eso. Entonces, lo que necesito saber es simple: ¿necesito liberarlo? – rustyshelf

0

Haces alloc la etiqueta, en un sentido, mediante la creación en IB.

Lo que hace IB, es ver sus IBOutlet y cómo se definen. Si tiene una variable de clase que IB es para asignar una referencia a algún objeto, IB enviará un mensaje de retención a ese objeto por usted.

Si está utilizando propiedades, IB hará uso de la propiedad que tiene que establecer el valor y no retener explícitamente el valor. Así que normalmente se marcará como propiedades IBOutlet retener:

@property (nonatomic, retain) UILabel *lblExample; 

Así, en caso éter (utilizando propiedades o no) debe llamar a la liberación en su dealloc.

+3

Esto no es correcto. Si no utiliza propiedades (o implementa sus propios métodos de acceso), entonces si debe o no liberar depende de la plataforma en la que se encuentre y cuál es su superclase. Si heredas de NSWindowController, por ejemplo, no lo liberas. – mmalc

0

Cualquier IBOutlet que es no es necesario liberar una subvista de la vista principal de su plumilla, ya que se les enviará el mensaje de liberación automática al momento de la creación del objeto. Los únicos IBOutlet que necesita liberar en su dealloc son objetos de nivel superior como controladores u otros NSObject. Todo esto se menciona en el documento de Apple vinculado anteriormente.

+3

Esto es realmente incorrecto. Si debe enviar objetos de nivel superior o no un mensaje de lanzamiento depende de qué plataforma esté utilizando y de qué clase herede el Propietario del archivo. Por ejemplo, si hereda de NSWindowController, no necesita liberarlos. – mmalc

3

La Parte

[anOutlet release], anOutlet = nil; 

es totalmente superflua si has escrito setView: correctamente.

+0

¿Qué quieres decir con esto? – Casebash

+1

En realidad, esto ha cambiado en 3.0 y más allá, lo entiendo. Ahora tenemos -viewDidUnload y es allí donde lanzamos los usuarios. –

0

Si no configura el IBOutlet como una propiedad sino simplemente como una variable de instancia, aún tiene que liberarlo. Esto se debe a que en initWithNib, la memoria se asignará para todos los IBOutlets. Este es uno de los casos especiales que debe liberar aunque no haya retenido ni haya asignado memoria en el código.

Cuestiones relacionadas