iphone - alloc+init con propiedad sintetizada: ¿provoca que el conteo de retención aumente en dos?
objective-c memory-management (4)
He visto el siguiente fragmento bastante:
En el encabezado:
SomeClass *bla;
@property(nonatomic,retain) SomeClass *bla;
En el archivo de implementación:
@synthesize bla;
y entonces
self.bla = [[SomeClass alloc] init];
Creo que esta asignación hace que el retener cuente para ''bla'' en dos; una vez a través de la llamada alloc / init, luego a través de retener que pedimos pasar a través del setter de propiedades sintetizadas.
Como resultado, normalmente declaro mis propiedades así:
En el encabezado:
SomeClass *_bla; // note the underscore
@property(nonatomic,retain) SomeClass *bla;
En el archivo de implementación:
@synthesize bla = _bla;
y entonces
_bla = [[SomeClass alloc] init];
Siempre que mi suposición inicial sea correcta, me interesaría saber si existe una forma "correcta" de hacerlo, es decir, la declaración, la inicialización y la administración de la memoria de las propiedades.
Sí, tienes razón, usar el setter sintetizado de una propiedad de retain
aumentaría el conteo de ref en una instancia que ya tienes (como alloc
implica propiedad).
Simplemente vaya con la segunda forma que mencionó en sus inicializadores:
_bla = [[SomeClass alloc] init];
... y recuerde corregir el conteo retenido de lo contrario, por ejemplo:
self.bla = [[[SomeClass alloc] init] autorelease];
Parece que el problema central aquí es un malentendido de la semántica de propiedad de objetos en Cocoa. Para cada init
, copy
o retain
llamado en un objeto debe realizarse una llamada para release
o release
autorelease
. Lo que sucede aquí es que la llamada a init
no tiene una llamada coincidente para release
o release
autorelease
.
Creo que lo que es confuso aquí es que la notación de puntos para la asignación de propiedades es azúcar sintáctica para una llamada a un método. Parece que es solo una tarea cuando en realidad es una llamada a un establecimiento de propiedades.
self.bla = [[SomeClass alloc] init];
no es lo mismo que:
bla = [[SomeClass alloc] init];
El primero se traduce en:
[self setBla: [[SomeClass] alloc] init]];
mientras que el último es literalmente una tarea.
Para solucionar su problema, todo lo que necesita hacer es asegurarse de que el código que llama a las llamadas init
autorelease
para que el recuento de autorelease
se autorelease
después de la llamada autorelease
por el colocador.
No hay doble conteo. El colocador creado por sintetizar hace una liberación antes de hacer un retener. Consulte la clase de Stanford sobre el objetivo c clase 3 como se menciona en el sitio web de Apple. También vale la pena señalar que, en el caso de iboutlets, no se necesita alloc init, ya que se realiza mediante la carga del archivo xib
Creo que esta asignación hace que el retener cuente para ''bla'' en dos;
Cierto.
Me interesaría saber si hay una forma "correcta" de hacer esto
Su último código es el correcto, pero no se recomienda el subrayado inicial. La propiedad y el ivar pueden compartir el mismo nombre. Sólo
@interface Foo : Bar {
SomeClass* bla;
}
@property (nonatomic, retain) SomeClass* bla;
@end
@implementation Foo
@synthesize bla;
-(id)init {
...
bla = [[SomeClass alloc] init];
...
}
-(void)dealloc {
[bla release];
...
[super dealloc];
}
es suficiente.
Algunas personas pueden usar
SomeClass* foo = [[SomeClass alloc] init];
self.bla = foo;
[foo release];
o
self.bla = [[[SomeClass alloc] init] autorelease];
en el método de entrada, pero lo desaconsejo fuertemente , ya que esto requiere innecesariamente muchos métodos, y no se puede garantizar el comportamiento del colocador .