2009-04-15 6 views
79

Ich verwende NSUSerDefaults, um Benutzereinstellungen zu speichern. Ich erinnere mich, irgendwo gelesen zu haben, dass das Setzen der Schlüssel als Konstanten eine gute Idee ist - und ich stimme zu. Der folgende Code ist, was ich habe zur Zeit:Verwenden eines konstanten NSString als Schlüssel für NSUserDefaults

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

Ich habe versucht, zu ändern, dies zu:

@implementation Controller 

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides"; 

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

Während diese Arbeit tut, es produziert "warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Ich bin daran interessiert, meinen Code frei von Compiler-Warnungen zu halten. Wie kann ich diese Warnung beheben?

Antwort

195

sollten Sie verwenden:

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

statt:

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 geschieht, weil setObject:forKey: erklärt sich wie folgt:

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

Es wird erwartet, dass das defaultName Argument von NSString * Typ zu sein. Wenn Sie stattdessen einen Zeiger auf eine Konstante übergeben, haben Sie etwas anderes angegeben.

Update: ich, dass diese Konstanten darauf hinweisen, sollten als static definiert werden, wenn sie nur aus einer einzigen Datei verwendet werden werden. Ich sage das, weil ich selbst auf dieses Problem gestoßen bin: Wenn Sie sie nicht als statisch deklarieren, dann werden sie im globalen Namespace existieren, und Sie werden nicht in der Lage sein, eine Variable mit demselben Namen in einer anderen Datei zu verwenden. Weitere Informationen finden Sie unter Constants in Objective-C. Um mit gutem Beispiel zu erklären, ist es das, was ich derzeit für Schlüssel verwenden, die ich nur in einer .m Datei verwenden müssen:

static NSString * const kSomeLabel = @"..."; 
+0

'NSString * const foo 'funktioniert, weil' NSString' unveränderlich ist und der Zeiger unveränderlich ist, so dass er niemals richtig geändert werden kann? Außerdem erinnere ich mich von C++, dass "const" implizit 'static' ist (eine Compiler-Optimierung), also muss man es nicht aufrufen. Trifft das auch hier zu? – Ternary

28

Verwenden const nicht mit Objective-C-Objekten, wurden sie nicht wirklich entworfen zu verwenden es. NSString Objekte (neben vielen anderen) sind bereits standardmäßig aufgrund ihres Designs unveränderlich, so dass sie const nutzlos machen.

Als e.James suggested können Sie einen NSString * const verwenden, der ein konstanter Zeiger auf eine NSString ist. Dies unterscheidet sich subtil von einer const NSString * (äquivalent zu NSString const *), die ein Zeiger auf eine Konstante NSString ist. Die Verwendung eines NSString * const verhindert, dass Sie kPoly neu zuweisen, um auf ein neues Objekt NSString zu zeigen.

+0

Guter Punkt über die Verwendung von const. Aus diesem Grund haben viele Objective-C-Klassen "Mutable" -Varianten. –

+1

Ich dachte, dass "const" auch bedeutet, dass du es nicht neu zuordnen kannst. Ich denke, ich hatte das falsch. –

5

ich auch die Konstante kräftigeren machen würde vorschlagen. Eine Konstante für die Anzahl der Seiten eines Polygons könnte von überall her kommen. Wie wäre es mit einem Vorschlag:

kDefaultsPolygonNumberOfSides; 

statt.

14

Für den Zugriff von anderen Klassen:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey; 

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSidesPrefsKey" 

Zugriff Nur innerhalb geschlossener aktuellen Klasse:

.m