Objective-C Language
Propriétés
Recherche…
Syntaxe
- @property ( optional_attributes, ... ) identifiant de type ;
- identificateur de @synthesize = optional_backing_ivar;
- identifiant dynamique
Paramètres
Attribut | La description |
---|---|
atomic | Implicite. Permet la synchronisation dans les méthodes d'accès synthétisées. |
nonatomic | Désactive la synchronisation dans les méthodes d'accesseur synthétisées. |
readwrite | Implicite. Synthétise getter, setter et back ivar. |
readonly | Synthétise uniquement la méthode getter et le support ivar, qui peuvent être assignés directement. |
getter= nom | Spécifie le nom de la méthode getter, implicite est propertyName . |
setter= nom | Spécifie le nom de la méthode setter, l'implicite est setPropertyName: Colon : doit faire partie du nom. |
strong | Implicite pour les objets sous ARC . La sauvegarde ivar est synthétisée en utilisant __strong , ce qui empêche la désallocation de l'objet référencé. |
retain | Synonyme de strong . |
copy | Même chose que strong , mais le composeur synthétisé appelle également -copy sur la nouvelle valeur. |
unsafe_unretained | Implicite, sauf pour les objets sous ARC. La sauvegarde ivar est synthétisée à l'aide de __unsafe_unretained , qui (pour obejcts) se traduit par un pointeur en suspens une fois que l'objet référencé est désalloué. |
assign | Synonyme de unsafe_unretained . Convient aux types sans objet. |
weak | Le backar ivar est synthétisé en utilisant __weak , donc la valeur sera annulée une fois que l'objet référencé sera désalloué. |
class | Les accesseurs de propriétés sont synthétisés en tant que méthodes de classe, au lieu de méthodes d'instance. Aucun stockage de sauvegarde n'est synthétisé. |
nullable | La propriété accepte les valeurs nil . Principalement utilisé pour les ponts rapides. |
nonnull | La propriété n'accepte pas les valeurs nil . Principalement utilisé pour les ponts rapides. |
null_resettable | La propriété accepte les valeurs nil dans setter, mais ne renvoie jamais de valeurs nil partir de getter. Votre implémentation personnalisée de getter ou setter doit garantir ce comportement. Principalement utilisé pour les ponts rapides. |
null_unspecified | Implicite. La propriété ne spécifie pas le traitement des valeurs nil . Principalement utilisé pour les ponts rapides. |
Quelles sont les propriétés?
Voici un exemple de classe qui comporte deux variables d’instance, sans utiliser les propriétés:
@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
C'est un code assez standard pour créer une variable d'instance simple. Vous devez créer la variable d'instance et créer des méthodes d'accès qui ne font rien sauf définir ou renvoyer la variable d'instance. Ainsi, avec Objective-C 2.0, Apple a introduit des propriétés qui génèrent automatiquement tout ou partie du code standard.
Voici la classe ci-dessus réécrite avec les propriétés:
@interface TestClass
@property NSString *someString;
@property int someInt;
@end
@implementation testClass
@end
Une propriété est une variable d'instance associée à des getters et des setters générés automatiquement. Pour une propriété appelée someString
, le getter et le setter sont appelés someString
et setSomeString:
respectivement. Le nom de la variable d'instance est, par défaut, le nom de la propriété préfixée par un trait de soulignement (la variable d'instance pour someString
est appelée _someString
, mais elle peut être remplacée par une directive @synthesize
dans la section @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
On peut accéder aux propriétés en appelant les getters et les setters:
[testObject setSomeString:@"Foo"];
NSLog(@"someInt is %d", [testObject someInt]);
On peut également y accéder en utilisant la notation par points:
testObject.someString = @"Foo";
NSLog(@"someInt is %d", testObject.someInt);
Getters et régleurs personnalisés
Les getters et setters de propriétés par défaut peuvent être remplacés:
@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
Cela peut être utile pour fournir, par exemple, une initialisation différée (en remplaçant le getter pour définir la valeur initiale s'il n'a pas encore été défini):
- (NSString *)someString {
if (_someString == nil) {
_someString = [self getInitialValueForSomeString];
}
return _someString;
}
Vous pouvez également créer une propriété qui calcule sa valeur dans le getter:
@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
Propriétés provoquant des mises à jour
Cet objet, Shape
possède une image
propriété qui dépend de numberOfSides
et de sideWidth
. Si l'un d'eux est défini, l' image
doit être recalculée. Mais le recalcul est probablement long et ne doit être effectué qu'une seule fois si les deux propriétés sont définies. Ainsi, la Shape
permet de définir les deux propriétés et de ne recalculer qu'une seule fois. Cela se fait en définissant directement la propriété ivars.
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
Lorsque des propriétés sont affectées à (à l'aide de object.property = value
), la méthode setter setProperty:
est appelée. Ce setter, même s'il est fourni par @synthesize
, peut être remplacé, comme c'est le cas pour numberOfSides
et sideWidth
. Toutefois, si vous définissez directement le paramètre ivar d'une propriété (via la property
si l'objet est self ou object->property
), il n'appelle pas getter ou setter, ce qui vous permet de faire des choses comme plusieurs jeux de propriétés contourner les effets secondaires causés par le passeur.