Использование константы 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(оптимизация компилятора), поэтому нет необходимости вызывать это. Это правда и здесь?
Ternary
32

Не используйте constс объектами Objective-C, они на самом деле не предназначены для его использования. NSStringобъекты (среди многих других) уже неизменяемы по умолчанию в силу их дизайна, поэтому создавать их constбесполезно.

Как предположил Э. Джеймс , вы можете использовать NSString * const, который является постоянным указателем на NSString. Это немного отличается от const NSString *(эквивалент NSString const *), который является указателем на константу NSString. Использование не NSString * constпозволяет переназначить kPolyуказатель на новый NSStringобъект.

Адам Розенфилд
источник
Хорошее замечание об использовании const. Вот почему многие классы Objective-C имеют "изменяемые" варианты.
e.James
2
Я думал, это constтакже означает, что вы не можете переназначить его. Думаю, я ошибся.
Дэн Розенстарк
18

Для доступа из других классов:

.час

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Для доступа только внутри текущего класса:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"
Malhal
источник
5

Я бы посоветовал даже сделать константу более наглядной. Константа для количества сторон многоугольника может поступать откуда угодно. Как насчет предложения:

kDefaultsPolygonNumberOfSides;

вместо.

Abizern
источник