2011-08-31 10 views
17

me dijeron por un fellow StackOverflow user que no debería utilizar el método getter cuando se libera una propiedad:¿Por qué no debería usar el getter para liberar una propiedad en Object-C?

@property(nonatmic, retain) Type* variable; 
@synthesize variable; 

// wrong 
[self.variable release]; 

// right 
[variable release]; 

Él no explicó en detalle por qué. Me parecen lo mismo. My iOS book dijo que el comprador de una propiedad se verá así:

- (id)variable { 
    return variable; 
} 

Así que ¿no significa esto [self variable], self.variable y variable son todos iguales?

+0

Esa es una recomendación muy peligrosa; el captador no siempre se verá así. De hecho, si fuera una propiedad 'atómica', sería -retain/-autorelease. – bbum

Respuesta

4

Un captador típica se verá de la misma familia:

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

tanto, si utiliza [self.variable release] usted tiene un adicional de retain y autorelease que realmente no necesita, cuando lo que desea es liberar el objeto y que causa el objeto que se lanzará más tarde de lo necesario (cuando se vacía el grupo de autorrelease).

Normalmente, se puede usar tanto self.variable = nil que tiene la ventaja de que también establece la variable a nil (evitando accidentes debido a referencia colgante), o [variable release] que es el más rápido y puede ser más apropiado en un método dealloc si su colocador tiene una lógica personalizada.

9

Opcionalmente, puede escribir el comportamiento del captador personalizado, lo que puede dar como resultado un comportamiento completamente diferente. Por lo tanto, no siempre se puede suponer que [variable release] tiene los mismos resultados que [self.variable release].

Además, puede escribir propiedades personalizadas sin un respaldo exclusivo que las respalde ... ¡puede volverse demasiado rápido si comienza a liberar objetos de referencias devueltas por getters!

Puede haber razones adicionales que estoy al tanto de ...

+0

Esto es cierto, pero no puedo imaginar qué tipo de getter alteraría la propiedad de una manera en que el usuario no podría liberarla). – Eimantas

+1

@Eimantas: No puedo, sin embargo, decir que estás liberando objetos a través de getters en su dealloc ... El código escrito en el getter personalizado puede intentar acceder a otros ivars que ya se han liberado, lo que da como resultado un bloqueo. ¡O a otros casos raros como ese! – MechEthan

+3

¿Quizás el getter podría devolver una copia autorrellenada? Sería una idea terrible, pero aún sería válida. Entonces, en ese caso, liberar el valor devuelto por el getter colisionaría su programa liberando un objeto en exceso. –

13

Para una propiedad retenida sin descriptor de acceso personalizado, puede liberar el objeto de:

self.variable = nil; 

Esto tiene el efecto de estableciendo el ivar (que puede no llamarse 'variable' si solo tiene propiedades declaradas) en cero y liberando el valor anterior.

Como han señalado otros, liberar directamente el ivar (si está disponible) o utilizar el método anterior está bien; lo que no debe hacer es invocar la liberación de la variable devuelta por un getter.

+0

Sabía que olvidé algo importante en mi respuesta ... voté tuyo porque es algo importante de entender. – MechEthan

+0

Leí en [lugares múltiples] (http://stackoverflow.com/questions/5737312/set-to-nil-in-viewdidunload-but-release-in-dealloc/5737438#5737438) que las propiedades deberían ser publicadas en ' dealloc' y puesto a nil en 'viewDidUnload'. – JoJo

+1

Si también tiene un ivar, puede liberarlo directamente. El punto es que no puede liberar lo que devuelve el captador, ya que no se garantiza que sea la variable subyacente real. Liberar directamente el ivar evita que se ejecute cualquier lógica personalizada en el setter, si no tiene ninguna, hace poca o ninguna diferencia. – jrturton

4

no todos los captadores tomar esta forma:

- (id)variable { return variable; } 

... que no es más que la forma más primitiva. las propiedades por sí solas deberían sugerir más combinaciones, que alteran la implementación. el acceso primitivo anterior no tiene en cuenta las expresiones idiomáticas utilizadas junto con la gestión de memoria, la atomicidad o la semántica de copia. la implementación también es frágil en las anulaciones de subclase.

algunos ejemplos realmente breves siguen; Obviamente, las cosas se vuelven más complejas en programas reales donde las implementaciones se vuelven considerablemente más complejas.

1) el captador no puede devolver la variable de instancia.una de varias posibilidades:

- (NSObject *)a { return [[a copy] autorelease]; } 

2) el colocador puede no retener la variable de instancia. una de varias posibilidades:

- (void)setA:(NSObject *)arg 
{ 
    ... 
    a = [arg copy]; 
    ... 
} 

3) se termina con la aplicación de gestión de memoria a través de su programa, que hace que sea difícil de mantener. la semántica de la clase (y la forma en que maneja el recuento ref variables de instancia) se debe mantener a la clase, y seguir las convenciones de resultados esperados:

- (void)stuff:(NSString *)arg 
{ 
    const bool TheRightWay = false; 
    if (TheRightWay) { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [string release]; 
     // - or - 
     NSMutableString * string = [[arg mutableCopy] autorelase]; 
     [string appendString:@"2"]; 
     self.a = string; 
    } 
    else { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [self.a release]; 
    } 
} 

no seguir estas reglas simples hace que su código sea difícil de mantener y depurar y doloroso de extender.

por lo que el resto es que desea que su programa sea fácil de mantener. Llamar lanzamiento directamente en una propiedad requiere que conozcas mucho contexto del funcionamiento interno de la clase; eso es obviamente malo y echa de menos los fuertes ideales del buen OOD.

también espera que los autores/subclassers/clientes para saber exactamente cómo la clase se desvía de la convención, que es tonta y consume mucho tiempo cuando surgen problemas y hay que volver a aprender todos los detalles internos cuando surgen problemas (que en algún momento)

estos son algunos ejemplos triviales de cómo la publicación de llamadas en el resultado de una propiedad presenta problemas. muchos problemas del mundo real son mucho más sutiles y difíciles de localizar.

Cuestiones relacionadas