Objective-C Language
Propiedades
Buscar..
Sintaxis
- @property ( optional_attributes, ... ) identificador de tipo ;
- @synthesize identifier = optional_backing_ivar ;
- identificador @dynamic;
Parámetros
Atributo | Descripción |
---|---|
atomic | Implícito. Habilita la sincronización en métodos de acceso sintetizados. |
nonatomic | Desactiva la sincronización en los métodos de acceso sintetizados. |
readwrite | Implícito. Sintetiza getter, setter y respaldo ivar. |
readonly | Sintetiza solo el método getter y el respaldo de ivar, que se pueden asignar directamente. |
getter= nombre | Especifica el nombre del método getter, implícito es propertyName . |
setter= nombre | Especifica el nombre del método de establecimiento, implícito es setPropertyName: Colon : debe ser parte del nombre. |
strong | Implícito para objetos bajo ARC . El respaldo ivar se sintetiza utilizando __strong , lo que evita la desasignación del objeto referenciado. |
retain | Sinónimo de strong . |
copy | Igual que strong , pero el definidor sintetizado también llama a la -copy en el nuevo valor. |
unsafe_unretained | Implícito, excepto para los objetos bajo ARC. El soporte ivar se sintetiza utilizando __unsafe_unretained , que (para objetos) da como resultado un puntero colgante una vez que el objeto referenciado se desasigna. |
assign | Sinónimo para unsafe_unretained . Adecuado para tipos sin objeto. |
weak | El respaldo de ivar se sintetiza utilizando __weak , por lo que el valor se __weak una vez que se desasigne el objeto al que se hace referencia. |
class | Los accesores de propiedades se sintetizan como métodos de clase, en lugar de métodos de instancia. No se sintetiza ningún almacenamiento de respaldo. |
nullable | La propiedad acepta valores nil . Utilizado principalmente para puentes rápidos. |
nonnull | La propiedad no acepta valores nil . Utilizado principalmente para puentes rápidos. |
null_resettable | La propiedad acepta valores nil en el establecedor, pero nunca devuelve valores nil de getter. Su implementación personalizada de getter o setter debe garantizar este comportamiento. Utilizado principalmente para puentes rápidos. |
null_unspecified | Implícito. La propiedad no especifica el manejo de valores nil . Utilizado principalmente para puentes rápidos. |
¿Qué son las propiedades?
Aquí hay una clase de ejemplo que tiene un par de variables de instancia, sin usar propiedades:
@interface TestClass : NSObject {
NSString *_someString;
int _someInt;
}
-(NSString *)someString;
-(void)setSomeString:(NSString *)newString;
-(int)someInt;
-(void)setSomeInt:(NSString *)newInt;
@end
@implementation TestClass
-(NSString *)someString {
return _someString;
}
-(void)setSomeString:(NSString *)newString {
_someString = newString;
}
-(int)someInt {
return _someInt;
}
-(void)setSomeInt:(int)newInt {
_someInt = newInt;
}
@end
Esto es bastante código repetitivo para crear una variable de instancia simple. Debe crear la variable de instancia y crear métodos de acceso que no hagan nada, excepto establecer o devolver la variable de instancia. Así que con Objective-C 2.0, Apple introdujo propiedades, que generan automáticamente parte o la totalidad del código repetitivo.
Aquí está la clase anterior reescrita con propiedades:
@interface TestClass
@property NSString *someString;
@property int someInt;
@end
@implementation testClass
@end
Una propiedad es una variable de instancia emparejada con captadores y definidores generados automáticamente. Para una propiedad llamada someString
, el getter y setter se llaman someString
y setSomeString:
respectivamente. El nombre de la variable de instancia es, de forma predeterminada, el nombre de la propiedad con un guión bajo (por lo que la variable de instancia para someString
se llama _someString
, pero esto se puede anular con una directiva @synthesize
en la sección @implementation
:
@synthesize someString=foo; //names the instance variable "foo"
@synthesize someString; //names it "someString"
@synthesize someString=_someString; //names it "_someString"; the default if
//there is no @synthesize directive
Se puede acceder a las propiedades llamando a los captadores y configuradores:
[testObject setSomeString:@"Foo"];
NSLog(@"someInt is %d", [testObject someInt]);
También se puede acceder a ellos usando notación de puntos:
testObject.someString = @"Foo";
NSLog(@"someInt is %d", testObject.someInt);
Capturadores personalizados y setters
Los captadores y definidores de propiedades predeterminados se pueden anular:
@interface TestClass
@property NSString *someString;
@end
@implementation TestClass
// override the setter to print a message
- (void)setSomeString:(NSString *)newString {
NSLog(@"Setting someString to %@", newString);
// Make sure to access the ivar (default is the property name with a _
// at the beginning) because calling self.someString would call the same
// method again leading to an infinite recursion
_someString = newString;
}
- (void)doSomething {
// The next line will call the setSomeString: method
self.someString = @"Test";
}
@end
Esto puede ser útil para proporcionar, por ejemplo, una inicialización perezosa (anulando al getter para establecer el valor inicial si aún no se ha establecido):
- (NSString *)someString {
if (_someString == nil) {
_someString = [self getInitialValueForSomeString];
}
return _someString;
}
También puedes hacer una propiedad que calcula su valor en el captador:
@interface Circle : NSObject
@property CGPoint origin;
@property CGFloat radius;
@property (readonly) CGFloat area;
@end
@implementation Circle
- (CGFloat)area {
return M_PI * pow(self.radius, 2);
}
@end
Propiedades que causan actualizaciones
Este objeto, Shape
tiene una image
propiedad que depende de numberOfSides
y sideWidth
. Si cualquiera de ellos está configurado, entonces la image
debe ser recalculada. Pero el recálculo es presumiblemente largo, y solo debe hacerse una vez si ambas propiedades están establecidas, por lo que la Shape
proporciona una manera de establecer ambas propiedades y solo recalcularlas una vez. Esto se hace estableciendo la propiedad ivars directamente.
En Shape.h
@interface Shape {
NSUInteger numberOfSides;
CGFloat sideWidth;
UIImage * image;
}
// Initializer that takes initial values for the properties.
- (instancetype)initWithNumberOfSides:(NSUInteger)numberOfSides withWidth:(CGFloat)width;
// Method that allows to set both properties in once call.
// This is useful if setting these properties has expensive side-effects.
// Using a method to set both values at once allows you to have the side-
// effect executed only once.
- (void)setNumberOfSides:(NSUInteger)numberOfSides andWidth:(CGFloat)width;
// Properties using default attributes.
@property NSUInteger numberOfSides;
@property CGFloat sideWidth;
// Property using explicit attributes.
@property(strong, readonly) UIImage * image;
@end
En Shape.m
@implementation AnObject
// The variable name of a property that is auto-generated by the compiler
// defaults to being the property name prefixed with an underscore, for
// example "_propertyName". You can change this default variable name using
// the following statement:
// @synthesize propertyName = customVariableName;
- (id)initWithNumberOfSides:(NSUInteger)numberOfSides withWidth:(CGFloat)width {
if ((self = [self init])) {
[self setNumberOfSides:numberOfSides andWidth:width];
}
return self;
}
- (void)setNumberOfSides:(NSUInteger)numberOfSides {
_numberOfSides = numberOfSides;
[self updateImage];
}
- (void)setSideWidth:(CGFloat)sideWidth {
_sideWidth = sideWidth;
[self updateImage];
}
- (void)setNumberOfSides:(NSUInteger)numberOfSides andWidth:(CGFloat)sideWidth {
_numberOfSides = numberOfSides;
_sideWidth = sideWidth;
[self updateImage];
}
// Method that does some post-processing once either of the properties has
// been updated.
- (void)updateImage {
...
}
@end
Cuando las propiedades se asignan a (usando object.property = value
), se llama al método setProperty:
Este configurador, incluso si lo proporciona @synthesize
, puede ser anulado, como lo es en este caso para numberOfSides
y sideWidth
. Sin embargo, si configura el ivar de una propiedad directamente (a través de la property
si el objeto es self, o object->property
), no llama al captador ni al establecedor, lo que le permite hacer cosas como conjuntos de propiedades múltiples que solo llaman una actualización o Evita los efectos secundarios causados por el colocador.