Pregunta

Esta es una práctica común que veo a menudo (incluso de un libro muy popular para desarrolladores de iPhone)

En el archivo .h:

@interface SomeViewController : UIViewController
{
  UIImageView *imgView;
}

En algún lugar del archivo .m:

imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
applicationFrame]];
[imgView setImage:[UIImage imageNamed:@"someimage.png"]];
[self addSubview:imgView];
[imgView release];

Y luego, vemos esto ...

- (void) dealloc
{
  [imgView release];
  [super dealloc];

} 

Dado que imgView tiene una asignación y un lanzamiento coincidentes, ¿es necesario el lanzamiento de imgView en dealloc?

¿Dónde se encuentra el imgView retenido por la llamada addSubview?

¿Fue útil?

Solución

Sí, ese código tiene problemas. lanza imgView demasiado pronto, lo que podría causar bloqueos en raras circunstancias almacena un objeto en una variable de instancia sin retenerlo, y generalmente trata de la gestión de la memoria de manera incorrecta.

Una forma correcta de hacer esto sería:

@interface SomeViewController : UIViewController
{
    UIImageView *imgView;
}
@property (nonatomic, retain) UIImageView *imgView;

Y en la implementación;

@synthesize imgView;

En algún lugar del módulo:

//Create a new image view object and store it in a local variable (retain count 1)
UIImageView *newImgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
newImgView.image = [UIImage imageNamed:@"someimage.png"];

//Use our property to store our new image view as an instance variable,
//if an old value of imgView exists, it will be released by generated method,
//and our newImgView gets retained (retain count 2)
self.imgView = newImgView;

//Release local variable, since the new UIImageView is safely stored in the
//imgView instance variable. (retain count 1)
[newImgView release];

//Add the new imgView to main view, it's retain count will be incremented,
//and the UIImageView will remain in memory until it is released by both the
//main view and this controller. (retain count 2)
[self.view addSubview:self.imgView];

Y el dealloc sigue siendo el mismo:

- (void) dealloc
{
    [imgView release];
    [super dealloc];
}

Otros consejos

El código es incorrecto. Terminarás liberando imgView después de que haya sido desasignado.

En su archivo .m, usted:

  1. alloc it - > usted lo posee
  2. agregarlo como una subvista - > usted y el UIView lo posee
  3. release it - > usted no es el propietario

Luego, en dealloc , release imgView aunque, como establecimos en el paso 3 anterior, no es el propietario. Cuando llame a [super dealloc] , la vista liberará todas sus subvistas y me imagino que obtendrá una excepción.

Si desea mantener un ivar de imgView , sugiero que no llame a release después de agregarlo como una subvista, y mantenga su dealloc lo mismo. De esa manera, incluso si imgView se elimina en algún momento de la jerarquía de vistas, todavía tendrá una referencia válida a ella.

El código es incorrecto, no deberías liberarlo en el método init, solo cuando se llama a dealloc (eso es si quieres mantenerlo como un ivar, no es necesario hacerlo a menos que necesites un puntero) en otra parte desde addSubview: conservará la vista para usted).

Creo que la razón por la que no se bloquea en realidad es porque aún está siendo retenida por la superclase (desde la llamada hasta addSubview :), por lo que cuando se publica en dealloc, en realidad eso está compensado. La vista probablemente se elimine a sí misma de la vista de supervisión cuando se desasigna inmediatamente después, por lo que cuando se llama a [super dealloc] , no se publica. Esa es mi corazonada, al menos.

El lanzamiento en init es incorrecto.

Usted mencionó " práctica común " y un libro sin nombre. Sugiero mirar los ejemplos canónicos de Apple: ViewTransitions es un buen ejemplo para este caso (y 2 vistas para arrancar;)

http://developer.apple.com/iphone/library /samplecode/ViewTransitions/index.html

(No tengo suficiente reputación para agregar comentarios todavía)

@bentford: corríjame si me equivoco, pero creo que para usar el establecedor sintetizado de la propiedad imgView, debe usar " self.imgView " ;:

self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]

Si no tienes self. , solo está usando el ivar, y no está obteniendo la retención adicional.

La respuesta básica es que solo debe haber un [imgView release] en el código de ejemplo ( si es después de addSubview o in dealloc ). Sin embargo, eliminaría [imgView release] de dealloc y lo dejaría después de addSubview .

Hay un retén en el iPhone; con didReceiveMemoryWarning , podría tener objetos ( incluyendo una vista completa ) liberados debajo de usted. Si tiene un conjunto de retenciones para toda la aplicación y no respeta la memoria, puede encontrar que la aplicación simplemente se está eliminando.

Un buen ejemplo es:
Si piensa en un conjunto anidado de 3 vistas, vea 1- > Ver 2- > Vista 3. A continuación, considere las llamadas ' viewDidLoad ' y ' viewDidUnload '. Si el usuario se encuentra actualmente en 'Vista 3', es posible que la Vista 1 esté descargada, y aquí es donde se pone desagradable.
 Si asignó un objeto dentro de viewDidLoad y no lo liberó después de agregarlo a la subvista, entonces su objeto no se libera cuando se descarga view1, pero aún se descarga view1.   viewDidLoad se ejecutará de nuevo y su código se ejecutará de nuevo, pero ahora tiene dos instancias de su objeto en lugar de una; un objeto estará en ninguna parte con la vista previamente descargada y el nuevo objeto será para la vista actualmente visible. Enjuague, haga espuma y repita, y encontrará que su aplicación falla debido a pérdidas de memoria.

En este ejemplo, si el bloque de código dado es volátil y tiene la posibilidad de ejecutarse nuevamente ( ya sea por memoria o por una vista descargada ), eliminaría [imgView release ]; de dealloc y dejarlo después de addSubView.

Aquí hay un enlace sobre conceptos básicos de retención / liberación: http://www.otierney.net/objective-c.html#retain

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top