Использование константы NSString в качестве ключа для NSUserDefaults

Я использую 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". Я очень хочу, чтобы мой код не был свободен от предупреждений компилятора. Как я могу исправить это предупреждение?

Ответ 1

Вы должны использовать:

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 = @"...";

Ответ 2

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

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

Ответ 3

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

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSidesPrefsKey"

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

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSidesPrefsKey"

Ответ 4

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

kDefaultsPolygonNumberOfSides;

вместо.

Ответ 5

Для получения дополнительной информации об этой проблеме есть замечательная статья о Википедии, объясняющая постоянный синтаксис с указателями: http://en.wikipedia.org/wiki/Const_correctness#Pointers_and_references