2010-10-13 16 views
5

tengo el siguiente en la cabecera:¿Cómo se implementa el método retener con @synthesize?

@property (nonatomic, retain) UIView *overlay; 

Y en la implementación:

@synthesize overlay; 

continuación:

UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
self.overlay = tempOverlay; 
[tempOverlay release]; 

no es la variable tempOverlay anterior innecesario? ¿No puedo hacer:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

Respuesta

11

Un colocador retenido sintetizado parece:

- (void)setValue: (id)newValue 
{ 
    if (value != newValue) 
    { 
     [value release]; 
     value = newValue; 
     [value retain]; 
    } 
} 

En su caso, tiene dos métodos válidos:

1) Crear una var temp, alloc/init (= retenida), fijado a la propiedad , lanzamiento.

IView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
self.overlay = tempOverlay; 
[tempOverlay release]; 

2) Sin temp var, se establece directamente en ivar.

overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

ACTUALIZACIÓN: Si utiliza el método 2), usted tiene que manejar de forma explícita el resto de la gestión de memoria (no sólo conserva), por la liberación de cualquier valor previo que podría tener antes si es necesario. Si lo hace solo una vez en init (por ejemplo), puede simplemente poner un [overlay release]; en dealloc.

+0

Si un setter retenido sintetizado parece que lo tienes, ¿qué ocurre la primera vez que se establece el valor? Si intenta liberar primero el valor anterior, ¿no se bloqueará con BAD ACCESS? O bien, ¿todas las propiedades reciben automáticamente un recuento de retención inicial de 1? – ma11hew28

+0

¿Debe usarse alguna vez el método 2, quizás la primera vez que se configura? Pero, si lo está configurando después de que ya se haya configurado, entonces el valor anterior no se liberará (a menos que se haga explícitamente). Entonces, eso causaría una pérdida de memoria, ¿correcto? – ma11hew28

+2

Inicialmente, el valor es nulo, y el envío de cualquier mensaje a nulo (incluido retener/liberar) no es posible devolver nada. – jv42

2

Usando el atributo especifica que retainretain debe invocarse en el nuevo objeto y el valor anterior se envía un release.

Por lo tanto, en su segundo bloque de código, el recuento de retención del objeto se convertiría en 2, ya que ya no lo suelta, y el colocador lo está reteniendo. Es poco probable que sea lo que quieres.

-2

Sí, puede asignar directamente el objeto recién creado al objeto overlay. Si lo desea, puede probar a se imprima la cuenta de retención del objeto

NSLog(@"count: %d", [overlay retainCount]); 
+0

-1 No entiende el punto. El objeto fue creado con alloc. Por lo tanto, es el propietario y debe liberarlo cuando haya terminado con lo que está en este caso. – JeremyP

+0

No lo creo. Ver la respuesta que di. – ma11hew28

1

Si asigna el objeto directamente a la propiedad, aún debe liberarlos:

self.overlay = [[[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)] autorelease]; 
+0

Esto debe ser incorrecto. Ver la respuesta que di. – ma11hew28

+0

Lo siento, no me desplacé a la derecha para ver el 'autorelease'. Esta es una solución correcta, pero quería liberar explícitamente el valor temporal después de establecer 'overlay'. – ma11hew28

1

Como su propiedad se define con (mantener) cualquier instancia se establece mediante el colocador sintetizado (a través de la sintaxis self.overlay) será automáticamente enviado un mensaje retener:

// You're alloc'ing and init'ing an object instance, which returns an 
// instance with a retainCount of 1. 
UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

// The overlay property is defined with (retain), so when you assign the new 
// instance to this property, it'll automatically invoke the synthesized setter, 
// which will send it a retain message. Your instance now has a retain count of 2. 
self.overlay = tempOverlay; 

// Send a release message, dropping the retain count to 1. 
[tempOverlay release]; 

Si se va a hacer:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

Su superposición tendría un conteo retenido de dos, lo que probablemente provocaría una fuga en algún momento de su aplicación.

0

Gracias por todas las respuestas.Tengo algunas afirmaciones contradictorias por lo que he comprobado lo siguiente en una UITableViewController:

- (id)initWithStyle:(UITableViewStyle)style { 
    if ((self = [super initWithStyle:style])) { 
     NSLog(@"count: %d", [overlay retainCount]); 
     self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
     NSLog(@"count: %d", [overlay retainCount]); 
     [overlay release]; NSLog(@"released once"); 
     NSLog(@"count: %d", [overlay retainCount]);  
     [overlay release]; NSLog(@"released twice"); 
     NSLog(@"count: %d", [overlay retainCount]); 
    } 
    return self; 
} 

Me dio la siguiente salida de la consola:

  • veces funcionó muy bien:

    count: 0 
    count: 2 
    released once 
    count: 1 
    released twice 
    count: 1 
    
  • Otras veces se estrelló:

    count: 0 
    count: 2 
    released once 
    count: 1 
    released twice 
    Program received signal: “EXC_BAD_ACCESS”. 
    

Sé que el método usando tempOverlay es correcto. Parece tan engorroso, pero lo prefiero a autorelease porque no entiendo cómo funciona autorelease o cuando se llama. Una cosa es segura. El código anterior es incorrecto porque no quiero que overlay tenga un conteo de retención de 2.

Lo raro es que no puedo soltarlo dos veces. Incluso cuando no se cuelga, el conteo retenido no disminuye.

De todos modos, supongo que me quedaré con el uso del tempOverlay por el momento.

+0

teniendo un conteo de retención de 2 es correcto en el código que tiene. una vez para el iVar retener, y una vez más para la llamada "alloc". – johnbakers

Cuestiones relacionadas