Використання константи NSString як ключа для NSUserDefaults


86

Я використовую NSUSerDefaults для зберігання налаштувань користувачів. Я пам’ятаю, десь читав, що встановлення клавіш як констант - це гарна ідея - і я погоджуюсь. Наступний код - це те, що я зараз маю:

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

Я спробував змінити це на:

@implementation Controller

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";

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

Хоча це працює, воно видає " warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Я прагну захистити свій код від попереджень компілятора. Як я можу виправити це попередження?

Відповіді:


207

Ви повинні використовувати:

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

замість:

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

Перший - це постійний вказівник на об'єкт NSString, тоді як другий - вказівник на постійний об'єкт NSString.

Це тонка різниця. Попередження компілятора відбувається, оскільки setObject:forKey:оголошується наступним чином:

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

Він очікує, що defaultNameаргумент має тип NSString *. Коли ви замість цього передаєте вказівник на константу, ви надаєте їй щось інше.

Оновлення: Я хочу зазначити, що ці константи слід визначати так,staticніби вони будуть використовуватися лише з одного файлу. Я кажу це тому, що сам натрапив на цю проблему: якщо ви не оголосите їх статичними, вони існуватимуть у глобальному просторі імен, і ви не зможете використовувати змінну з таким самим іменем в іншому файлі. див. Константи в Objective-C для отримання додаткової інформації. Щоб пояснити на прикладі, це те, що я зараз використовую для ключів, які мені потрібно використовувати лише в одному.mфайлі:

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

1
NSString * const fooпрацює, оскільки NSStringє незмінним, а вказівник незмінним, тому він ніколи не може змінитися правильно? Крім того, я згадую з C ++, що constнеявно static(оптимізація компілятора), тому не потрібно його називати. Це правда і тут?
Тернар

32

Не використовуйте constоб’єкти Objective-C, вони насправді не призначені для використання. NSStringоб'єкти (серед багатьох інших) вже незмінні за замовчуванням в силу їх конструкції, тому робити їх constмарно.

Як запропонував e.James , ви можете використовувати an NSString * const, який є постійним вказівником на an NSString. Це тонко відрізняється від const NSString *(еквівалента NSString const *), який є покажчиком на константу NSString. Використання NSString * constзапобіжника перешкоджає перепризначенню kPolyвказувати на новий NSStringоб’єкт.


Хороший момент щодо використання const. Тому багато класів Objective-C мають варіанти, що змінюються.
e.James

2
Я думав, це constтакож означає, що ви не можете перепризначити його. Я здогадуюсь, що я помилився.
Dan Rosenstark

18

Для доступу з інших класів:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Для доступу лише всередині поточного класу:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

5

Я б запропонував навіть зробити константу більш описовою. Константа кількості сторін багатокутника може надходити з будь-якого місця. Як пропозицію, як щодо:

kDefaultsPolygonNumberOfSides;

замість цього.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.