2009-04-15 15 views
79

Estoy usando NSUSerDefaults para almacenar las preferencias del usuario. Recuerdo haber leído en alguna parte que establecer las teclas como constantes es una buena idea, y estoy de acuerdo. El siguiente código es lo que tengo actualmente:Usar una NSString constante como la clave para NSUserDefaults

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

He intentado cambiar esto:

@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". Me encanta mantener mi código libre de advertencias del compilador. ¿Cómo puedo solucionar esta advertencia?

Respuesta

195

que puedes usar:

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

en lugar 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 sucede porque setObject:forKey: se declara como sigue:

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

Se espera que el argumento defaultName a ser de tipo NSString *. Cuando en cambio pasas un puntero a una constante, le has dado algo diferente.

Actualización: Quiero señalar que estas constantes deben ser definidas como static si sólo van a ser utilizados dentro de un solo archivo. Digo esto porque me he encontrado con este problema: si no los declaras como estáticos, entonces existirán en el espacio de nombres global, y no podrás usar una variable con el mismo nombre en otro archivo. ver Constants in Objective-C para más información. Para explicar el ejemplo, esto es lo que yo uso actualmente para llaves que sólo tendrá que utilizar en una .m archivo:

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

'NSString * const foo' funciona porque' NSString' es inmutable y el puntero es inmutable por lo que nunca puede cambiar correctamente? Además, recuerdo de C++ que 'const' es implícitamente' static' (una optimización del compilador) por lo que no es necesario llamarlo. ¿Es eso cierto aquí también? – Ternary

28

No utilice const con objetos Objective-C, no fueron realmente diseñados para utilizar eso. NSString objetos (entre muchos otros) ya son inmutables por defecto en virtud de su diseño, por lo que const es inútil.

Como e.James suggested, puede usar un NSString * const, que es un puntero constante a NSString. Esto es sutilmente diferente de const NSString * (equivalente a NSString const *), que es un puntero a una constante NSString. El uso de un NSString * const le impide reasignar kPoly para apuntar a un nuevo objeto NSString.

+0

Buen punto sobre el uso de const. Es por eso que muchas clases de Objective-C tienen variantes "Mutable". –

+1

Pensé que 'const' también significa que no puedes reasignarlo. Creo que estaba equivocado. –

5

Yo sugeriría incluso haciendo la constante más descriptivo. Una constante para el número de lados de un polígono podría venir de cualquier parte. Como sugerencia, ¿qué tal:

kDefaultsPolygonNumberOfSides; 

en su lugar.

14

Para el acceso de otras clases:

.h

extern NSString * const PolygonNumberOfSidesPrefsKey; 

.m

NSString * const PolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSidesPrefsKey" 

Para el acceso sólo dentro de la clase actual:

.m

static NSString * const kPolygonNumberOfSidesPrefsKey = @"PolygonNumberOfSidesPrefsKey" 
Cuestiones relacionadas