Verwenden eines konstanten NSString als Schlüssel für NSUserDefaults

86

Ich verwende NSUSerDefaults, um Benutzereinstellungen zu speichern. Ich erinnere mich, dass ich irgendwo gelesen habe, dass es eine gute Idee ist, die Schlüssel als Konstanten festzulegen - und ich stimme zu. Der folgende Code ist der, den ich derzeit habe:

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

Ich habe versucht, dies zu ändern in:

@implementation Controller

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";

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

Während dies funktioniert, erzeugt es " warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Ich möchte meinen Code frei von Compiler-Warnungen halten. Wie kann ich diese Warnung beheben?

Olly
quelle

Antworten:

207

Du solltest benutzen:

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

anstatt:

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

Der erste ist ein konstanter Zeiger auf ein NSString-Objekt, während der zweite ein Zeiger auf ein konstantes NSString-Objekt ist.

Es ist ein subtiler Unterschied. Die Compiler-Warnung wird angezeigt, weil sie setObject:forKey:wie folgt deklariert ist:

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

Es wird erwartet, dass das defaultNameArgument vom Typ ist NSString *. Wenn Sie stattdessen einen Zeiger auf eine Konstante übergeben, haben Sie ihr etwas anderes gegeben.

Update: Ich möchte darauf hinweisen, dass diese Konstanten so definiert werden sollten, als würdenstaticsie nur aus einer einzigen Datei heraus verwendet. Ich sage dies, weil ich selbst auf dieses Problem gestoßen bin: Wenn Sie sie nicht als statisch deklarieren, sind sie im globalen Namespace vorhanden, und Sie können keine Variable mit demselben Namen in einer anderen Datei verwenden. Weitere Informationen findenSie unter Konstanten in Ziel-C . Um dies anhand eines Beispiels zu erklären, verwende ich derzeit Schlüssel, die ich nur in einer.mDatei verwenden muss:

static NSString * const kSomeLabel = @"...";
James
quelle
1
NSString * const foofunktioniert, weil NSStringunveränderlich ist und der Zeiger unveränderlich ist, so dass er sich nie richtig ändern kann? Ich erinnere mich auch an C ++, constdas implizit ist static(eine Compiler-Optimierung), so dass es nicht nötig ist, es aufzurufen. Gilt das auch hier?
Ternary
32

Nicht constmit Objective-C-Objekten verwenden, sie wurden nicht wirklich dafür verwendet. NSStringObjekte (unter anderem) sind aufgrund ihres Designs bereits standardmäßig unveränderlich, so dass constes nutzlos ist, sie herzustellen.

Wie von e.James vorgeschlagen , können Sie ein verwenden NSString * const, das ein konstanter Zeiger auf ein ist NSString. Dies unterscheidet sich geringfügig von a const NSString *(äquivalent zu NSString const *), das ein Zeiger auf eine Konstante ist NSString. Die Verwendung von NSString * constverhindert, dass Sie neu zuweisen kPoly, um auf ein neues NSStringObjekt zu verweisen .

Adam Rosenfield
quelle
Guter Punkt zur Verwendung von const. Aus diesem Grund haben viele Objective-C-Klassen "Mutable" -Varianten.
e.James
2
Ich dachte, das constbedeutet auch, dass Sie es nicht neu zuweisen können. Ich glaube, ich hatte das falsch gemacht.
Dan Rosenstark
18

Für den Zugriff von anderen Klassen:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Für den Zugriff nur innerhalb der aktuellen Klasse:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"
malhal
quelle
5

Ich würde vorschlagen, die Konstante noch aussagekräftiger zu gestalten. Eine Konstante für die Anzahl der Seiten eines Polygons kann von überall kommen. Wie wäre es mit:

kDefaultsPolygonNumberOfSides;

stattdessen.

Abizern
quelle