objective c - Propiedades e instancias variables en Objective-C
cocoa cocoa-touch (5)
Estoy bastante confundido acerca de las propiedades y variables de instancia en Objective-C.
Estoy aproximadamente a la mitad de la "Programación Cocoa para Mac OS X" de Aaron Hillegass y todo es lógico. Declararías una clase como esta:
@class Something;
@interface MyClass : NSObject {
NSString *name;
NSArray *items;
Something *something;
IBOutlet NSTextField *myTextField;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSArray *items;
Como otros objetos necesitan manipular nuestras variables de instancia de
name
yitems
, usamos@property
/@synthesize
para generar@synthesize
/ mutators para ellos. Dentro de nuestra clase, no usamos los accessors / mutators, simplemente interactuamos directamente con la variable de instancia.something
es solo una variable de instancia que vamos a usar en nuestra clase, y dado que nadie más necesita usarla, no creamos un par de accesadores y mutadores para ella.Necesitamos interactuar con un campo de texto en nuestra UI, por lo que declaramos un
IBOutlet
, lo conectamos y terminamos.
Todo muy lógico.
Sin embargo, en el mundo del iPhone, las cosas parecen ser diferentes. Las personas declaran propiedades para cada variable de instancia única, declaran propiedades para IBOutlets
y usan accessors / mutators para interactuar con variables de instancia dentro de la clase (por ejemplo, escribirían [self setName:@"Test"]
vez de name = @"Test"
) .
¿Por qué? Que esta pasando? ¿Estas diferencias son específicas de iPhone? ¿Cuáles son las ventajas de declarar propiedades para todas las variables de instancia, declarar propiedades para IBOutlets
y usar IBOutlets
/ mutadores dentro de su propia clase?
Sin embargo, en el mundo del iPhone, las cosas parecen ser diferentes. Las personas declaran propiedades para cada variable de instancia única, declaran propiedades para
IBOutlets
y usan accessors / mutators para interactuar con variables de instancia dentro de la clase (por ejemplo, escribirían[self setName:@"Test"]
vez dename = @"Test"
) .
Eso no es específico de iPhone. Excepto en los métodos init
y el método dealloc
, es una buena práctica usar siempre sus accesorios. El principal beneficio, especialmente en Mac (con Cocoa Bindings), es que el uso de sus accesorios significa notificaciones gratuitas de KVO.
La razón por la que las personas "declaran propiedades para cada variable de instancia única" probablemente sea que todas sus variables de instancia son cosas que desean exponer como propiedades. Si tenían algo que quisieran mantener en privado, no declararían una propiedad en el archivo de encabezado. (Sin embargo, pueden hacer una propiedad para él en una extensión de clase en el archivo de implementación, para obtener las notificaciones gratuitas de KVO mencionadas anteriormente).
Declarar propiedades para puntos de venta es excesivo, en mi opinión. No veo un punto para eso. Si no hace una propiedad, el cargador de nib configurará la salida mediante acceso directo a variable de instancia, lo cual está bien para esa tarea.
En el mundo de iPhone, no hay un recolector de basura disponible. Tendrá que administrar cuidadosamente la memoria con el recuento de referencias. Con eso en mente, considere la diferencia entre:
name = @"Test";
y
self.name = @"Test";
// which is equivalent to:
[self setName: @"Test"];
Si establece directamente la variable de instancia, sin consideración previa, perderá la referencia al valor anterior y no podrá ajustar su conteo retenido (debe release
d manualmente). Si accede a ella a través de una propiedad, se gestionará automáticamente, junto con el aumento del recuento de retención del objeto recién asignado.
El concepto fundamental no es específico de iPhone, pero se vuelve crucial en un entorno sin el recolector de basura.
Puedes escribir así
//MyClass.h
@class Something;
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *items;
@end
//MyClass.m
@interface MyClass()
@property (nonatomic, strong) IBOutlet NSTextField *myTextField;
@property (nonatomic, strong) Something *something;
@end
Sugeriría que el desarrollo moderno ha hecho un gran esfuerzo para identificar, definir y aplicar las mejores prácticas.
Entre estas mejores prácticas encontramos continuidad y consistencia.
Además de discutir sobre el uso de accessors en los métodos init
y dealloc
, los accessors generalmente deberían usarse todo el tiempo (dentro y fuera de una clase) por los beneficios que ofrecen, incluyendo encapsulation , implementaciones var polimórficas (que permiten abstraer y refactorizar) y para facilitar esas mejores prácticas de continuidad y consistencia. Los beneficios fundamentales de un lenguaje orientado a objetos entran en juego cuando se hacen las cosas de esta manera y se explota la plenitud de las capacidades del lenguaje. Siempre ser coherente en la codificación de uno es un beneficio a menudo mencionado, como cualquier programador de alto nivel por lo general dará fe.
Las propiedades se usan para generar accesadores para variables de instancia, no hay magia sucediendo.
Puede implementar los mismos accesos a mano.
Puede encontrar en el libro de Aaron Hillegass ejemplos de 3 estrategias de gestión de la memoria para variables de miembros. Ellos son assign/copy/retain
. Usted selecciona uno de esos según lo requerido para la variable dada.
Supongo que entiendes la gestión de la memoria en Objective-c ...
Los usuarios ocultan la complejidad y las diferencias de la administración de memoria para cada variable.
Por ejemplo:
name = @"Test"
es una asignación simple, el name
ahora contiene referencia a NSString @"Test"
. Sin embargo, puede decidir usar copy
o retain
. No importa qué versión de administración de memoria elija, el programador oculta la complejidad y siempre accede a la variable con (o similar):
[self setName:@"Test"]
[self name]
Ahora setName:
podría usar assign/copy or retain
y no tiene que preocuparse por eso.
Supongo que los tutoriales de iPhone usan propiedades para facilitar que los nuevos desarrolladores salten a través de la administración de la memoria (aunque es útil generar accesores adecuados con propiedades en lugar de implementarlos a mano cada vez).