Utilisation d'une NSString constante comme clé pour NSUserDefaults

86

J'utilise NSUSerDefaults pour stocker les préférences de l'utilisateur. Je me souviens avoir lu quelque part que définir les clés en tant que constantes est une bonne idée - et je suis d'accord. Le code suivant est ce que j'ai actuellement:

[[NSUserDefaults standardUserDefaults]
        setObject:[NSNumber numberWithInt:polygon.numberOfSides] 
           forKey:@"polygonNumberOfSides"];

J'ai essayé de changer cela en:

@implementation Controller

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";

-(void)savePolygonInfo {
    [[NSUserDefaults standardUserDefaults]
            setObject:[NSNumber numberWithInt:polygon.numberOfSides] 
               forKey:kPolygonNumberOfSides];
}

Bien que cela fonctionne, cela produit " warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Je tiens à garder mon code exempt d'avertissements du compilateur. Comment puis-je corriger cet avertissement?

Olly
la source

Réponses:

207

Tu devrais utiliser:

NSString * const kPolygonNumberOfSides = @"..."; // const pointer

au lieu de:

NSString const * kPolygonNumberOfSides = @"..."; // pointer to const

Le premier est un pointeur constant vers un objet NSString, tandis que le second est un pointeur vers un objet NSString constant.

C'est une différence subtile. L'avertissement du compilateur se produit car il setObject:forKey:est déclaré comme suit:

- (void)setObject:(id)value forKey:(NSString *)defaultName;

Il s'attend à ce que l' defaultNameargument soit de type NSString *. Lorsque vous passez plutôt un pointeur vers une constante, vous lui avez donné quelque chose de différent.

Mise à jour: Je tiens à souligner que ces constantes doivent être définies commestaticsi elles allaient être utilisées uniquement à partir d'un seul fichier. Je dis cela parce que j'ai moi-même rencontré ce problème: si vous ne les déclarez pas comme statiques, ils existeront dans l'espace de noms global et vous ne pourrez pas utiliser une variable avec le même nom dans un autre fichier. voir Constantes en Objective-C pour plus d'informations. Pour expliquer par exemple, voici ce que j'utilise actuellement pour les clés que je n'ai besoin d'utiliser que dans un seul.mfichier:

static NSString * const kSomeLabel = @"...";
e.James
la source
1
NSString * const foofonctionne car il NSStringest immuable et le pointeur est immuable donc il ne peut jamais changer, correct? Aussi, je me souviens de C ++ qui constest implicitement static(une optimisation du compilateur) donc pas besoin de l'appeler. Est-ce vrai ici aussi?
Ternary
32

Ne pas utiliser constavec des objets Objective-C, ils n'étaient pas vraiment conçus pour l'utiliser. NSStringles objets (parmi tant d'autres) sont déjà immuables par défaut en raison de leur conception, il constest donc inutile de les fabriquer .

Comme e.James l'a suggéré , vous pouvez utiliser un NSString * const, qui est un pointeur constant vers un fichierNSString . C'est subtilement différent de a const NSString *(équivalent à NSString const *), qui est un pointeur vers une constante NSString. L'utilisation de a NSString * constvous empêche de réaffecter kPolypour pointer vers un nouvel NSStringobjet.

Adam Rosenfield
la source
Bon point sur l'utilisation de const. C'est pourquoi beaucoup de classes Objective-C ont des variantes "Mutable".
e.James
2
Je pensais que cela constsignifie également que vous ne pouvez pas le réaffecter. Je suppose que je me suis trompé.
Dan Rosenstark
18

Pour l'accès depuis d'autres classes:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Pour accéder uniquement à l'intérieur de la classe actuelle:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"
malhal
la source
5

Je suggérerais même de rendre la constante plus descriptive. Une constante pour le nombre de côtés d'un polygone peut provenir de n'importe où. À titre de suggestion, que diriez-vous:

kDefaultsPolygonNumberOfSides;

au lieu.

Abizern
la source