2009-04-15 6 views
79

Używam NSUSerDefaults do przechowywania preferencji użytkownika. Pamiętam, że czytałem gdzieś, że ustawienie kluczy jako stałych to dobry pomysł - i zgadzam się. Poniższy kod jest co obecnie mam:Używanie stałego NSString jako klucza dla NSUserDefaults

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

Próbowałem zmieniając to:

@implementation Controller 

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides"; 

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

Choć działa, produkuje "warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Chciałbym, aby mój kod był wolny od ostrzeżeń kompilatora. Jak mogę naprawić to ostrzeżenie?

Odpowiedz

195

Należy użyć:

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

zamiast:

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

Pierwszym jest stałym wskaźnikiem do obiektu NSString, podczas gdy druga jest wskaźnik do stałej obiektu NSString.

To subtelna różnica. Ostrzeżenie kompilatora Dzieje się tak dlatego setObject:forKey: jest zadeklarowana następująco:

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

ona spodziewa się defaultName argument być typu NSString *. Kiedy zamiast tego podajesz wskaźnik do stałej, dałeś mu coś innego.

Aktualizacja: Chcę podkreślić, że te stałe powinny być zdefiniowane jako static jeśli są one tylko będzie używany z poziomu jednego pliku. Mówię to, ponieważ sam natknąłem się na ten problem: jeśli nie zadeklarujesz ich jako statycznych, będą one istnieć w globalnym obszarze nazw, a nie będziesz mógł użyć zmiennej o tej samej nazwie w innym pliku. Aby uzyskać więcej informacji, patrz Constants in Objective-C. Aby wyjaśnić na przykładzie, to co ja obecnie używać do kluczy, że wystarczy użyć jednego .m pliku:

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

'NSString * const foo' działa, ponieważ' NSString' jest niezmienny, a wskaźnik jest niezmienny, więc nigdy nie może zmienić się poprawnie? Ponadto, pamiętam z C++, że 'const' jest niejawnie' static' (optymalizacja kompilatora), więc nie trzeba go wywoływać. Czy to również tutaj jest prawdą? – Ternary

28

Nie używaj const z obiektów Objective-C, nie były one rzeczywiście przeznaczone do stosowania to. NSString obiekty (spośród wielu innych) są już domyślnie niezmienne ze względu na ich konstrukcję, więc ich zbędne staje się const.

Jako e.James suggested można użyć NSString * const, który jest stałym wskaźnikiem do NSString. Jest to subtelnie odmienne od const NSString * (równoważne NSString const *), które jest wskaźnikiem do stałej NSString. Użycie numeru NSString * const uniemożliwi ponowne przypisanie wartości kPoly w celu wskazania nowego obiektu NSString.

+0

Dobra uwaga na temat korzystania z const. Dlatego wiele klas Objective-C ma warianty "Mutable". –

+1

Myślałem, że 'const' oznacza również, że nie można go ponownie przypisać. Chyba źle to zrobiłem. –

5

Sugerowałbym nawet podejmowania stałej bardziej opisowe. Stała dla liczby boków wieloboku może pochodzić z dowolnego miejsca. Jako sugestię, możesz wpisać:

kDefaultsPolygonNumberOfSides; 

zamiast tego.

14

uzyskać dostęp z innych klas:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey; 

.M

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSidesPrefsKey" 

za dostęp tylko wewnątrz bieżącej klasy:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSidesPrefsKey"