2009-05-15 7 views
7

¿Cuándo es necesario para las propiedades de clase? Por ejemplo:Cuándo usar self en las propiedades de clase?

self.MyProperty = @"hi there"; 

vs

MyProperty = @"hi there"; 

MyProperty es un NSString establecer como (no atómica, copia). ¿Hay alguna diferencia en la gestión de memoria para los dos anteriores?

¿Qué sucede cuando no hay ninguna propiedad y la variable MyProperty se declara en el archivo de encabezado? ¿Se necesita una propiedad si nunca se hace referencia fuera de la clase? ¿Hace una diferencia en la administración de la memoria?

Respuesta

8

Sí, hay una diferencia tanto para la memoria como para el rendimiento.

MyProperty = @"hi there"; 

Esto se considera una asignación directa. Prácticamente no hay memoria o impacto en el rendimiento. Por supuesto, eso no quiere decir que es la mejor práctica - que es una cuestión diferente :)

@property(nonatomic, copy) NSString *MyProperty; 
// ... 
self.MyProperty = @"hi there"; 

Esta declaración tiene un impacto significativo sobre la memoria y el rendimiento. Esto es esencialmente equivalente a:

-(void)setMyProperty(NSString *)newValue { 
    if (MyProperty != newValue) { 
     [MyProperty release]; 
     MyProperty = [newValue copy]; 
    } 
} 

El valor antiguo es liberado y el nuevo valor se copia en MyProperty. Esto es aceptable y especialmente típico cuando se trata de cadenas cuando la cadena que se asigna es mutable (es decir, podría cambiar más adelante).

Si, como en su ejemplo, simplemente está asignando una cadena estática (@ "hi there"), no hay nada de malo en asignar directamente el valor de cadena; es más eficiente, sin embargo, la diferencia en el rendimiento es trivial.

Puede declarar una propiedad con @property como conservar, copiar o asignar (se asigna por defecto). A continuación, puede generar métodos de "acceso" (getter/setter) utilizando @synthesize. Esto es lo que se genera la incubadora métodos parecen que cuando lo hace:

// @property(nonatomic, assign) 
-(void)setMyProperty(NSString *)newValue { 
    MyProperty = newValue; 
} 

// @property(nonatomic, retain) 
-(void)setMyProperty(NSString *)newValue { 
    if (property != newValue) { 
     [property release]; 
     property = [newValue retain]; 
    } 

// @property(nonatomic, copy) 
-(void)setMyProperty(NSString *)newValue { 
    if (property != newValue) { 
     [property release]; 
     property = [newValue copy]; 
    } 
} 

Más información sobre ObjectiveC Declared Properties.

"Puede utilizar las directivas @synthesize y @dynamic en bloques @implementation para desencadenar acciones específicas del compilador Tenga en cuenta que no se requiere para cualquier declaración dada @property

Importante:.. Si no se especifica o bien @ sintetizar o @dynamic para una propiedad en particular, debe proporcionar una implementación de método getter y setter (o solo getter en el caso de una propiedad de solo lectura) para esa propiedad ".

En otras palabras, si declara una propiedad pero no sintetiza la propiedad, no podrá usar [self MyProperty] o self.MyProperty a menos que defina los métodos 'MyProperty' y 'setMyProperty'. Si no declaras una propiedad, simplemente tienes una variable de instancia.

Nota: @dynamic no genera los accesos. Realmente se usa si está resolviendo dinámicamente (es decir, mágicamente) los métodos de acceso mediante el código de carga o la resolución dinámica de métodos.

+0

"Prácticamente no hay memoria ... impacto." Esto definitivamente es incorrecto. Si asigna directamente , no se sorprenda si el valor se reemplaza por algo extraño. El uso de una propiedad, incluso para una variable utilizada solo dentro de la clase, resuelve el problema de que se le asigne algo más a la dirección de su variable ss espacio y conserva la integridad del valor de la propiedad. – 4thSpace

+3

El "impacto" que describes no tiene nada que ver con la memoria o el rendimiento. La mala práctica, que noté en consecuencia, es una pregunta diferente;) Su comentario es incorrecto. En la pregunta, la propiedad es NSString y todas las asignaciones son constantes: @ "hi there" es una constante de NSString, no un objeto.Si escribe una aplicación que establece un valor en @ "una cadena", ya sea mediante asignar, copiar o retener, la variable siempre apuntará al mismo espacio de direcciones en la memoria. Las propiedades se utilizan para exponer variables de instancia, no gestión de memoria o direccionamiento. – nessence

1

Para la segunda parte de la pregunta, la definición de propiedad no es necesaria, es una ayuda para nosotros. La directiva @synthesize en la propiedad genera métodos de acceso para las propiedades por lo que no tenemos que hacerlo de forma manual, y porque:

Este código indica al compilador que genere , o sintetizar, el descriptor de acceso métodos. El compilador generará los métodos de acceso usando algoritmos bien probados y rápidos que son listos para multi-core y entornos de subprocesos múltiples, incluyendo variables de bloqueo en métodos setter. El uso de propiedades no solo reduce la cantidad de código que tiene que escribir , sino que reemplaza ese código con los mejores accesos posibles para los sistemas modernos de múltiples núcleos . Más tarde, si necesita proporcionar una implementación alternativa para un acceso de propiedad , simplemente puede agregar el código apropiado a su clase.

http://developer.apple.com/leopard/overview/objectivec2.html

El nonatomic se evitará el uso de bloqueo cuando se accede a las variables, si no se especifica nada, entonces por defecto es atomic. El bloqueo es útil en sistemas multiproceso. La copia especifica qué código se debe generar para los descriptores de acceso, copy copiará el objeto, retain retendrá el nuevo objeto y liberará el antiguo, assign es bueno para variables simples como int para simplemente asignar valores. Así que cuando defina su propiedad como lo hizo por encima de (nonatomic,copy) y luego use self.MyProperty = @"Hey" en realidad está llamando al acceso generado que hará una copia de la nueva variable en lugar de simplemente asignarla. Puede anular el acceso y agregarle control.

Debido a lo anterior, diría que definir la propiedad tiene beneficios incluso cuando la variable no se usa fuera de la clase.

Creo que para acceder a las propiedades debe usar self.MyProperty en lugar de solo MyProperty pero no puedo indicarle por qué. podría ser algo que ver con el hecho de que el compilador generará a partir

self.MyProperty = @"Hey"; 

esto:

[self setMyProperty: @"Hey"]; 

Pero yo sólo estoy especulando aquí.

Ya sea que llame a self.MyProperty o MyProperty, no debería afectar la administración de la memoria (aún preferiría la primera - self.MyProperty).

Consulte Objective-C 2.0 Overview para obtener una descripción de alto nivel de Apple.

+0

Parece que hay alguna relación con la gestión de la memoria. Si tiene una clase con un init personalizado, que asigna cadenas a las propiedades de cadena, cuando hace PropertyA = @ "hola allí; en lugar de self.PropertyA = @" hola allí "; y así sucesivamente con todas las propiedades, la persona que llama podría tener esas propiedades reasignadas sin sospechar en algún momento (no de las acciones de la persona que llama). En lugar de escribir NSString en las propiedades, podría ser NSArray, NSDictionary o NSNumber con "inválido" válido. Por alguna razón, algo reclama ese espacio de direcciones particular – 4thSpace

7

La diferencia es que

self.MyProperty = @"hi there" 

es llamada punto-notación que llamará al descriptor de acceso generada, que se encargará de los retener los recuentos correctamente (equivalente a [setMyProperty auto: @ "Hola"]), mientras

MyProperty = @"hi there" 

es una asignación directa a la variable de miembro, que no libera el valor antiguo, retener la nueva, o hacer cualquier otra cosa que su descriptor de acceso hace (por ejemplo, si tiene un colocador personalizado que hace trabajo extra)

Así que sí, hay una gran diferencia en la gestión de la memoria y en el comportamiento en general entre los dos. La última forma es casi siempre incorrecta, a menos que sepa específicamente por qué lo está haciendo y que usted maneja los recuentos de retención correctamente.

1

Como complemento a las otras respuestas, trate de pensar en ello de esta manera:

self.MyProperty = @"hi there"; 

o

[self setMyProperty:@"hi there"]; 

(que son equivalentes) tanto llamar a un método, mientras que

MyProperty = @"hi there"; 

Simplemente establece una variable.

3

Si usa el Key-Value Observing automático (o cualquier tecnología Cocoa que se base en él, como encuadernaciones, ...), también es importante utilizar el colocador. El observador no recibiría ninguna notificación si asigna al ivar. Si vincula "MyProperty" a un NSTextfield y cambia su "MyProperty" ivar mediante código, el campo de texto enlazado aún mostraría el valor anterior ya que no recibió ninguna notificación de cambio.

+0

te refieres con "... asignar al ivar"? – 4thSpace

+0

estableciendo un valor para una variable de instancia en lugar de usar el conjunto de accesos. –

0

¿Todavía no está claro cuándo utilizar los accesos y cuándo realizar la asignación directa en ivars? He visto muchos ejemplos de Apple que acceden directamente a los ivars. Así que usar propiedades para todos los ivars parece excesivo pedante.

Parece que solo los ivars significativos que deben durar más tiempo y que se accede al exterior tienden a usar las propiedades.

Agradeceríamos a algunos gurús de Cocoa para intervenir y aclarar.

+0

Por las razones que he comentado en la tercera publicación, las propiedades son muy necesarias. – 4thSpace

+0

No es una violación para los objetos acceder directamente a sus propios ivars. Todavía es más limpio usar accesorios/propiedades en ese caso, pero generalmente es un gran error de diseño que un objeto acceda a los ivars de otros * objetos. – Chuck

2

Para acceso variable, a menudo no es necesario utilizar la notación de puntos. Por lo tanto, en el código generado por las plantillas de XCode, verá cosas como:

[flipsideViewController viewWillAppear:YES]; 

no hay necesidad de escribir self.flipsideViewController aquí, debido a que el método de acceso normalmente no hace nada, excepto la entrega que la variable.

lo tanto, una buena regla general es utilizar la notación de punto cuando se está configurando una variable (a menos que sea absolutamente necesario que quiere hacer su propio retención y liberación), pero no cuando estás acceder a ella:

self.aString = @"Text text text"; 
NSLog (aString); // No need for self.aString here 
NSString* tmpString = aString; // Here neither 

al utilizar tipos no-objeto, como int o flotar o muchos otros, usted puede conseguir lejos con no usar el método de notación de puntos/definidor. En estos casos, no hay nada que retener, por lo que el método setter hará poco aparte de simplemente asignar el valor.

Sin embargo,, los getters y setters sintetizados hacen más que solo retener y soltar. Como otros han mencionado, también son el motor que mantiene el sistema KVO en funcionamiento. Por lo tanto, debe utilizar los ajustadores adecuados incluso en ints, flotadores y el resto.

¿Qué pasa con los accesorios?En contextos más avanzados, una clase puede responder a una solicitud del valor de una variable incluso cuando la variable no existe. Para citar el exaltado manual de Objective-C, las clases pueden proporcionar "implementaciones de métodos directamente o en tiempo de ejecución utilizando otros mecanismos [que simples métodos de acceso] como la carga dinámica de código o la resolución de métodos dinámicos".

(Una forma de implementar este tipo de respuesta sobre la marcha de los mensajes está reemplazando métodos NSObject como methodSignatureForSelector: y forwardInvocation:.)

Por esta razón, el uso de interfaces correctamente declarados (ya sea sintetizado o no) siempre es una buena idea cuando trabajas en algo grande. Pero está completamente bien acceder a ivars directamente, siempre y cuando los establezcas en usando la API adecuada.

(Nota: No soy un gurú de cacao, por lo que las correcciones son más que bienvenidos.)

+0

Gracias. ¿Qué es exactamente un ivar vs. propiedad/uno mismo? – 4thSpace

+1

"ivar" = Variable de instancia: una ranura de memoria reservada cuando se crea una instancia de una clase para contener un valor o un puntero. La declaración de propiedad es solo un protocolo, a través del cual las clases pueden establecer, acceder u observar vlaues de forma estandarizada. Los métodos de propiedad se * suelen * sintetizar y se basan en un ivar, pero no * tienen * que ser. Puede escribir sus propios métodos (@dynamic en lugar de @synthesize) para gestionar una propiedad y calcular los valores sobre la marcha (utilizando el cobro cuando corresponda). Por ejemplo, las propiedades frame/bounds/center de UIView podrían compartir un ivar y tener getters y setters especializados para mantenerlo. – Felixyz

+1

Más aclaración: cuando usa self.aVariable, está accediendo al ivar mediante métodos en el objeto self. (si usa @synthesize, no los verá en el código fuente, ya que se generan en tiempo de compilación). Cuando utiliza un Variable, simplemente tiene acceso al valor del ivar directamente, sin ningún método de envío. – Felixyz

1

Ésta es una cuestión de edad, a pesar de que solía ser "¿Cuándo escribo [self setMyProperty:@"hi there"]?" (Tenga en cuenta que self.MyProperty = @"hi there" es exactamente equivalente a esto.)

La respuesta que siempre he escuchado (y que tiene sentido) es siempre utilice el descriptor de acceso; nunca escriba MyProperty = @"hi there". Hay varias razones:

  1. La gestión de la memoria se maneja para usted; no tiene que preocuparse por la retención/liberación/copia adecuada.
  2. Es más fácil modificar su código en el futuro; Si en algún momento se da cuenta de que cambiar MyProperty necesita tener un efecto secundario particular, puede agregar al método setter sin buscar cada vez que configure MyProperty.
  3. Si alguna vez tiene problemas con MyProperty, es fácil agregar el código de registro al colocador (o incluso al eliminador) para descubrirlo cada vez que se lo cambia (o incluso se accede).

Resumen: es más seguro y más flexible para siempre [self setMyProperty:@"hi there"] uso o self.MyProperty = @"hi there", y nunca se uso MyProperty = @"hi there".

Cuestiones relacionadas