2010-07-16 5 views
17

He seeen el siguiente fragmento de un poco:alloc + init con propiedad sintetizada: ¿provoca que la cuenta de retención aumente en dos?

En el encabezado:

SomeClass *bla; 
@property(nonatomic,retain) SomeClass *bla; 

En el archivo de implementación:

@synthesize bla; 

y luego

self.bla = [[SomeClass alloc] init]; 

I piense que esta asignación hace que el retener cuente para 'bla' por 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 como esta:

En el encabezado:

SomeClass *_bla; // note the underscore 
@property(nonatomic,retain) SomeClass *bla; 

En el archivo de implementación:

@synthesize bla = _bla; 

y luego

_bla = [[SomeClass alloc] init]; 

Pr Supongamos que mi suposición inicial es 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?

+0

En primer lugar, invitamos a Stack Overflow. Una de las cosas que es importante hacer en Stack es aceptar respuestas que funcionen para usted. Es importante para quienes responden y para su propia reputación. – smathy

Respuesta

8

Sí, tiene razón: usar el setter sintetizado de una propiedad retain aumentaría el recuento de ref en una instancia que ya posee (como alloc implica propiedad).

ir sólo con la segunda forma que usted ha mencionado en sus inicializadores:

_bla = [[SomeClass alloc] init]; 

... y recordar para fijar la cuenta de retención de otro modo, por ejemplo:

self.bla = [[[SomeClass alloc] init] autorelease]; 
8

creo que esto asignación pone el retener contar para 'bla' por dos;

Es cierto.

estaría interesado en escuchar si hay manera 'correcta' de hacer esto

Su última pieza de código es la forma correcta, pero no se recomienda el subrayado inicial. La propiedad y el ivar pueden compartir el mismo nombre. Solo

@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 utilizar

SomeClass* foo = [[SomeClass alloc] init]; 
self.bla = foo; 
[foo release]; 

o

self.bla = [[[SomeClass alloc] init] autorelease]; 

en el método -init, pero fuertemente desalentar, ya que esto llama innecesariamente muchos métodos, and you cannot guarantee the behavior of the setter.

+0

Wao - mi primera publicación en stackoverflow, y dos respuestas en 5 minutos. ¡Gracias a los dos! – patschiboy

+6

Los dos patrones que desaconseja firmemente son perfectamente aceptables y normales en la mayoría de los casos. La respuesta a la que vinculó se relaciona ** solo ** con el uso de descriptores de acceso para establecer objetos en los métodos 'init' y' dealloc'. En cualquier otro lado, la recomendación de Apple es usar siempre los accesadores para acceder a las variables de instancia. – JeremyP

+0

JeremyP tiene razón, y por esa razón, esto no debe considerarse una respuesta correcta. – Felixyz

3

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 invocados en un objeto, debe realizarse una llamada a release o autorelease. Lo que sucede aquí es que la llamada al init no tiene una llamada correspondiente a release o 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 anterior se traduce en:

[self setBla: [[SomeClass] alloc] init]]; 

mientras que el último es literalmente una asignación.

Para solucionar el problema con todo lo que realmente necesita hacer es asegurarse de que el código que llama init llamadas autorelease de modo que la cuenta de retención se disminuye después de la retain llamada por el colocador.

-3

No hay recuento doble. 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

+0

Votado por error. [[xxx alloc] init] devuelve un objeto con un conteo de retención de 1, que debe ser contrarrestado en algún punto. Si almacena el resultado en una propiedad retenida, entonces establece inmediatamente la propiedad retenida en cero, tiene una pérdida de memoria. – gnasher729

Cuestiones relacionadas