2010-02-18 18 views
5

Dada la siguiente definición de la propiedad:Objective-C Propiedades y Gestión de memoria

@property (nonatomic,retain) MyObject* foo; 

tiene el siguiente código causar una pérdida de memoria:

self.foo = [[MyObject alloc] init]; 

?

Parece que la llamada alloc incrementa el conteo de retención en el objeto a 1, luego el retener dentro del setter de propiedad lo aumenta a 1. Pero dado que el recuento inicial nunca se reduce a 0, el objeto se mantendrá incluso cuando el yo es liberado ¿Es ese análisis correcto?

Si es así, parece que tengo dos alternativas:

self.foo = [[[MyObject alloc] init] autorelease]; 

que no se recomienda en el iPhone por razones de rendimiento, o:

MyObject* x = [[MyObject alloc] init]; 
self.foo = x 
[x release]; 

que es un poco engorroso. ¿Hay otras alternativas?

Respuesta

2

tiene usted razón, self.foo = [[MyObject alloc] init]; pierde memoria. Ambas alternativas son correctas y se pueden usar. Con respecto al autorelease en una declaración de este tipo: tenga en cuenta que el objeto se liberará por el grupo de autorremisión tan pronto como finalice el ciclo de ejecución actual, pero probablemente se conservará mucho más tiempo por self, por lo que no hay problema con el uso de memoria picos aquí.

3

¿Hay alguna alternativa?

No vas a ser capaz de escribir gran parte de una aplicación de iPhone sin necesidad de utilizar autorelease y la biblioteca de Cocoa Touch los utiliza en muchos lugares. Comprenda qué está haciendo (agregue el puntero a una lista para eliminar en el siguiente fotograma) y evite usarlo en bucles ajustados.

Puede usar el método de clase en MyObject que hace alloc/init/autorelease para que lo limpie.

+ (MyObject *)object { 
    return [[[MyObject alloc] init] autorelease]; 
} 

self.foo = [MyObject object]; 
+0

Esta es una gran alternativa que ahorra tiempo al crear instancias. –

3

La forma más fácil de administrar una propiedad retenida en el iPhone es la siguiente (autorelease no es tan malo como usted piensa, al menos para la mayoría de usos):

-(id)init { 
    if (self = [super init]) { 
     self.someObject = [[[Object alloc] init] autorelease]; 
    } 
    return self; 
} 

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

Los autorelease libera la referencia a la instancia flotante que está asignada al self.object que conserva su propia referencia, dejándole con la referencia que necesita (someObject). Luego, cuando se destruye la clase, se libera la única referencia restante, destruyendo el objeto.

Como se describe en otra respuesta, también puede crear uno o más mensajes de "constructor" para crear y liberar automáticamente los objetos con parámetros opcionales.

+(Object)object; 
+(Object)objectWithCount:(int)count; 
+(Object)objectFromFile:(NSString *)path; 

Se podría definir como éstos:

// No need to release o if fails because its already autoreleased 
+(Object)objectFromFile:(NSString *)path { 
    Object *o = [[[Object alloc] init] autorelease]; 
    if (![o loadFromFile:path]) { 
     return nil; 
    } 
    return o; 
} 
+0

-1 para no llamar '[super init]' ni '[super dealloc]', que es peligroso. – MrMage

+0

Mi error, simplemente estaba señalando el método de asignación SomeObject. Código actualizado –

+0

Todavía está mal, el método de facto 'init' implica asignar el valor de retorno de' [super init] 'a' self'. – dreamlax

Cuestiones relacionadas