Usando um NSString constante como a chave para NSUserDefaults

86

Estou usando NSUSerDefaults para armazenar as preferências do usuário. Lembro-me de ter lido em algum lugar que definir as chaves como constantes é uma boa ideia - e eu concordo. O código a seguir é o que eu tenho atualmente:

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

Tentei mudar isso para:

@implementation Controller

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";

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

Enquanto isso funciona, ele produz " warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Estou ansioso para manter meu código livre de avisos do compilador. Como posso corrigir esse aviso?

Olly
fonte

Respostas:

207

Você deveria usar:

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

ao invés de:

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

O primeiro é um ponteiro constante para um objeto NSString, enquanto o segundo é um ponteiro para um objeto NSString constante.

É uma diferença sutil. O aviso do compilador acontece porque setObject:forKey:é declarado da seguinte maneira:

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

É esperar que o defaultNameargumento seja do tipo NSString *. Ao passar um ponteiro para uma constante, você deu algo diferente.

Atualização: quero salientar que essas constantes devem ser definidas comostaticse fossem usadas apenas em um único arquivo. Digo isso porque eu mesmo já passei por esse problema: se você não os declarar como estáticos, eles existirão no namespace global e você não poderá usar uma variável com o mesmo nome em outro arquivo. consulte Constantes em Objective-C para obter mais informações. Para explicar por exemplo, isso é o que uso atualmente para as chaves que só preciso usar em um.marquivo:

static NSString * const kSomeLabel = @"...";
e.James
fonte
1
NSString * const foofunciona porque NSStringé imutável e o ponteiro é imutável, então nunca pode mudar correto? Além disso, lembro-me do C ++ que consté implicitamente static(uma otimização do compilador), então não há necessidade de chamá-lo. Isso também é verdade aqui?
Ternário
32

Não use constcom objetos Objective-C, eles não foram realmente projetados para usá-lo. NSStringobjetos (entre muitos outros) já são imutáveis ​​por padrão em virtude de seu design, portanto, torná-los consté inútil.

Como e.James sugeriu , você pode usar um NSString * const, que é um ponteiro constante para um NSString. Isso é sutilmente diferente de a const NSString *(equivalente a NSString const *), que é um ponteiro para uma constante NSString. O uso de a NSString * constimpede que você reatribua kPolypara apontar para um novo NSStringobjeto.

Adam Rosenfield
fonte
Bom ponto sobre o uso de const. É por isso que muitas classes Objective-C têm variantes "Mutáveis".
e.James
2
Achei que isso consttambém significa que você não pode reatribuí-lo. Acho que entendi errado.
Dan Rosenstark
18

Para acesso de outras classes:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Para acesso apenas dentro da classe atual:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"
Malhal
fonte
5

Eu sugeriria até mesmo tornar a constante mais descritiva. Uma constante para o número de lados de um polígono pode vir de qualquer lugar. Como sugestão, que tal:

kDefaultsPolygonNumberOfSides;

em vez de.

Abizern
fonte