2009-04-29 10 views
11

Ejemplo:¿Por qué debería un getter auto implementado retener y liberar automáticamente el objeto devuelto?

- (NSString*) title { 
    return [[title retain] autorelease]; 
} 

El colocador realmente retenida ya, ¿verdad? y en realidad nadie debería pasar por alto al Setter ... así que me pregunto por qué el getter no solo devuelve el objeto. En realidad ya está retenido. ¿O esto solo sería necesario en caso de que, mientras tanto, otros objetos pasen al colocador?

Respuesta

12

Desde aquí http://www.macosxguru.net/article.php?story=20030713184140267

- (id)getMyInstance 
    { 
     return myInstanceVar ; 
    } 

o

- (id)getMyInstance 
{ 
    return [[myInstanceVar retain] autorelease] ; 
} 

Cuál es la diferencia? El segundo permite que la persona que llama obtenga una variable de instancia de un objeto contenedor, deseche el contenedor y continúe jugando con la variable de instancia hasta la próxima versión de la agrupación autorretratada actual, sin que la versión de la variable de instancia lo afecte indirectamente generada por la liberación de su contenedor:

aLocalVar = [aContainer getAnInstanceVar] ; 
[aContainer release]; 
doSomething(aLocalVar); 

Si el "get" se implementa en la primera forma, se debe escribir:

aLocalVar = [[aContainer getAnInstanceVar] retain]; 
[aContainer release]; 
doSomething(aLocalVar); 
[aLovalVar release]; 

la primera forma es un poco más eficiente en términos de velocidad de ejecución del código Sin embargo, si está escribiendo marcos para ser utilizados por otros, tal vez debería recomendarse la segunda versión: hace la vida un poco más fácil para las personas que usan su marco: no tienen que pensar demasiado acerca de lo que están haciendo ... ;) Si elige la primera versión de estilo, indíquela claramente en su documentación ... Sea cual sea la forma que elija, recuerde que cambiar de la versión 1 a la versión 2 es guardar para el código de cliente, cuando regrese de la versión 2 a la 1 romper el código de cliente existente ...

0

No he visto este patrón antes, pero me parece bastante sin sentido. Supongo que la intención es mantener el valor devuelto seguro si el código del cliente llama "liberación" en el objeto principal. Realmente no duele nada, pero dudo que esa situación surja a menudo en bibliotecas bien diseñadas.


Ah, ok. de la documentación a la que smorgan se vinculó, parece que este es ahora uno de los métodos que Apple recomienda actualmente que la gente use. Creo que yo prefiero la versión de la vieja escuela:

- (NSString *) value 
{ 
    return myValue; 
} 

- (void) setValue: (NSString *) newValue 
{ 
    if (newValue != myValue) 
    { 
     [myValue autorelease]; // actually, I nearly always use 'release' here 
     myValue = [newValue retain]; 
    } 
} 
+0

Eso depende. Es un requisito absoluto para las propiedades a las que se puede acceder desde múltiples hilos, por ejemplo. En términos más generales, las situaciones que no aparecen a menudo son las que conducen a scratchers de cabeza realmente molestos. –

+0

Creo que veo lo que está diciendo, con respecto a varios subprocesos, ya que podría tener varios grupos de versiones independientes y ejecutar bucles. Todavía creo que la liberación automática en setter tiene más sentido en ese caso. –

+0

Y en el caso del acceso de subprocesos múltiples, suelo utilizar [obj copy]: tener instancias separadas de objetos elimina cualquier posibilidad de conflicto. –

7

No es sólo para los casos en los que alguien suelte el contenedor, ya que en ese caso es más obvio que se deben conservar el objeto a sí mismos. Considere este código:

NSString* newValue = @"new"; 
NSString* oldValue = [foo someStringValue]; 
[foo setSomeStringValue:newValue]; 
// Go on to do something with oldValue 

Esto parece razonable, pero si ni el colocador ni el comprador utiliza autorelease la parte "Vamos a hacer algo" probablemente se bloqueará, porque oldValue ahora ha sido desasignado (nadie suponiendo que los demás se habían conservado eso). Por lo general, desea utilizar la Técnica 1 o la Técnica 2 del Apple's accessor method examples para que el código como el anterior funcione como la mayoría de la gente espera.

3

comparar este código

return [[title retain] release]; // releases immediately 

con este

return [[title retain] autorelease]; // releases at end of current run loop (or if autorelease pool is drained earlier) 

El segundo garantiza que un cliente tendrá un objeto no dealloced a trabajar.

Esto puede ser útil en una situación como esta (código de cliente):

NSString *thing = [obj title]; 
[obj setTitle:nil]; // here you could hit retainCount 0! 
NSLog(@"Length %d", [thing length]); // here thing might be dealloced already! 

La retener (y el uso de autorelease en lugar de release) en su método de title evita que el código de la voladura. El objeto liberado automáticamente no tendrá su método release llamado hasta DESPUÉS de que se complete la ejecución de la pila de llamadas actual (final del ciclo de ejecución actual). Esto le da a todos el código del cliente en la pila de llamadas la posibilidad de usar este objeto sin preocuparse de que se desasigne.

Lo importante a recordar: Esto no es Java, Ruby o PHP. El hecho de que tenga una referencia a un objeto en su variable [sic] NO garantiza que no lo desasistirá de usted. Tienes que retenerlo, pero , entonces debes recordar soltarlo. Autorelease le permite evitar esto. Debería usar siempre usar liberación automática a menos que esté tratando con propiedades o bucles con muchas iteraciones (y probablemente ni siquiera a menos que ocurra un problema).

+0

También vea mi pregunta aquí: http://stackoverflow.com/questions/3816898/methods-that-call-methods-basics-of-autorelease –

Cuestiones relacionadas