Usando una NSString constante como clave para NSUserDefaults

86

Estoy usando NSUSerDefaults para almacenar las preferencias del usuario. Recuerdo haber leído en alguna parte que establecer las claves como constantes es una buena idea, y estoy de acuerdo. El siguiente código es el que tengo actualmente:

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

Intenté cambiar esto a:

@implementation Controller

NSString const *kPolygonNumberOfSides = @"polygonNumberOfSides";

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

Si bien esto funciona, produce " warning: passing argument 1 of 'objectForKey:' discards qualifiers from pointer target type". Estoy dispuesto a mantener mi código libre de advertencias del compilador. ¿Cómo puedo solucionar esta advertencia?

Olly
fuente

Respuestas:

207

Deberías usar:

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

en vez de:

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

El primero es un puntero constante a un objeto NSString, mientras que el segundo es un puntero a un objeto NSString constante.

Es una diferencia sutil. La advertencia del compilador ocurre porque setObject:forKey:se declara de la siguiente manera:

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

Espera que el defaultNameargumento sea de tipo NSString *. Cuando, en cambio, pasa un puntero a una constante, le ha dado algo diferente.

Actualización: quiero señalar que estas constantes deben definirse comostaticsi solo fueran a usarse desde un solo archivo. Digo esto porque yo mismo me he encontrado con este problema: si no los declara como estáticos, existirán en el espacio de nombres global y no podrá usar una variable con el mismo nombre en otro archivo. consulte Constantes en Objective-C para obtener más información. Para explicarlo con un ejemplo, esto es lo que uso actualmente para las claves que solo necesito usar en un.marchivo:

static NSString * const kSomeLabel = @"...";
e.James
fuente
1
NSString * const foofunciona porque NSStringes inmutable y el puntero es inmutable, por lo que nunca puede cambiar correctamente? Además, recuerdo de C ++ que constes implícitamente static(una optimización del compilador), por lo que no es necesario mencionarlo. ¿Es eso cierto aquí también?
Ternario
32

No lo use constcon objetos Objective-C, en realidad no fueron diseñados para usarlo. NSStringlos objetos (entre muchos otros) ya son inmutables por defecto en virtud de su diseño, por lo que hacerlos constes inútil.

Como sugirió e.James , puede usar an NSString * const, que es un puntero constante a un NSString. Esto es sutilmente diferente de a const NSString *(equivalente a NSString const *), que es un puntero a una constante NSString. El uso de a NSString * constevita que reasigne kPolypara apuntar a un nuevo NSStringobjeto.

Adam Rosenfield
fuente
Buen punto sobre el uso de const. Es por eso que muchas clases de Objective-C tienen variantes "Mutables".
e.James
2
Pensé que eso consttambién significa que no puedes reasignarlo. Supongo que me equivoqué.
Dan Rosenstark
18

Para acceder desde otras clases:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey;

.metro

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"

Para acceder solo dentro de la clase actual:

.metro

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSides"
malhal
fuente
5

Sugeriría incluso hacer la constante más descriptiva. Una constante para el número de lados de un polígono podría provenir de cualquier lugar. Como sugerencia, ¿qué tal:

kDefaultsPolygonNumberOfSides;

en lugar.

Abizern
fuente