J'ai défini une classe dans laquelle j'aimerais qu'une propriété publique apparaisse comme si elle était soutenue par une NSArray
. C’est assez simple, mais dans mon cas, le support réel ivar est un NSMutableArray
:
@interface Foo
{
NSMutableArray* array;
}
@property (nonatomic, retain) NSArray* array;
@end
Dans mon fichier d'implémentation (*.m
), je @synthesize
la propriété, mais je suis immédiatement confronté à des avertissements, car utiliser self.words
revient à essayer de modifier une NSArray
.
Quelle est la bonne façon de faire cela?
Merci!
Je déclarerais une readonly
NSArray
dans votre en-tête et remplacerais le getter pour que ce tableau renvoie une copie d'une NSMutableArray
privée déclarée dans votre implémentation. Considérer ce qui suit.
Foo.h
@interface Foo
@property (nonatomic, retain, readonly) NSArray *array;
@end
Foo.m
@interface Foo ()
@property (nonatomic, retain) NSMutableArray *mutableArray
@end
#pragma mark -
@implementation Foo
@synthesize mutableArray;
- (NSArray *)array
{
return [[self.mutableArray copy] autorelease];
}
@end
Fondamentalement, placez la propriété NSArray dans une catégorie dans votre fichier d’en-tête et la propriété NSMutableArray dans une extension class dans votre fichier d’implémentation. Ainsi...
Foo.h:
@interface Foo
@end
@interface Foo (Collections)
@property (nonatomic, readonly, strong) NSArray *someArray;
@end
Foo.m
@interface Foo ()
@property (nonatomic, readwrite, strong) NSMutableArray *someArray;
@end
Simple:
1) N'utilisez pas une propriété quand ce n'en est pas une.
2) Le code se simplifie pour:
- (NSArray *)currentArray {
return [NSArray arraywithArray:mutableArray]; // need the arrayWithArray - otherwise the caller could be in for surprise when the supposedly unchanging array changes while he is using it.
}
- (void)setArray:(NSArray *)array {
[mutableArray setArray:array];
}
Quand l'objet est alloué créer le tableau, quand il meurt, dealloc le tableau.
Lorsque des effets importants se produisent à la simple utilisation d'un '.' opérateur, il est facile de négliger le code extrêmement inefficace. Les accessoires ne sont que ça. De plus, si quelqu'un appelle aFoo.array, le contrat consiste à avoir accès aux membres du tableau de foo, mais il ne s'agit en réalité que d'une copie au moment de l'appel. La différence est suffisamment réelle pour causer des bogues dans les autres implémentations publiées ici.
Mise à jour: cette réponse n'est plus valide. Utilisez l’une des solutions suggérées ci-dessous.
Ces jours-ci, vous pouvez faire ce qui suit:
Foo.m:
@implementation Foo {
NSMutableArray* _array;
}
@end
Foo.h:
@interface Foo
@property (readonly, strong) NSArray* array;
@end
Vous pouvez toujours adresser _array mutable par ivar depuis l’intérieur de l’implémentation et de l’extérieur, il sera accessible via une propriété immuable. Malheureusement, cela ne garantit pas que les autres utilisateurs ne pourront pas le transtyper vers NSMutableArray et le modifier. Pour une meilleure protection contre les idiots, vous devez définir la méthode d'accès et renvoyer une copie immuable, mais cela peut s'avérer très coûteux dans certains cas.
En fait, je suis d’accord avec l’un des commentaires ci-dessus selon lequel il est préférable d’utiliser des méthodes simples d’accesseur si vous devez renvoyer des données en lecture seule, c’est nettement moins ambigu.
En effet, votre propriété doit correspondre au type de classe de l'IVAR.
Une solution possible/solution de contournement:
//Foo.h:
@interface Foo
{
NSMutableArray* mutableArray;
}
@property (readwrite, nonatomic, retain) NSArray* array;
//or manual accessor declarations, in case you're picky about wrapper-properties.
@end
//Foo.m:
@interface Foo ()
@property (readwrite, nonatomic, retain) NSMutableArray* mutableArray;
@end
@implementation
@synthesize mutableArray;
@dynamic array;
- (NSArray *)array {
return [NSArray arrayWithArray:self.mutableArray];
}
- (void)setArray:(NSArray *)array {
self.mutableArray = [NSMutableArray arrayWithArray:array];
}
@end
Vous ajoutez une propriété privée mutableArray
dans une extension de classe et vous transmettez simplement la variable publique array
à votre propriété mutable privée.
Avec les extensions linguistiques les plus récentes d’ObjC, j’ai tendance à supprimer le
{
NSMutableArray* mutableArray;
}
ivar bloc entièrement, si possible.
Et définir l’ivar à travers la synthèse, en tant que tel:
@synthesize mutableArray = _mutableArray;
qui générera une instance NSMutableArray *_mutableArray;
pour vous.
Réponse la plus simple: votre type de propriété (NSArray) ne correspond pas à votre type de variable d'instance (NSMutableArray).
C’est une autre bonne raison pour laquelle vous ne devez pas définir vos propres variables de sauvegarde. Laissez @synthesize configurer vos variables d'instance; ne le faites pas à la main.