2009-12-21 23 views
40

En Objective-C, entiendo que la directiva @ "foo" define una constante NSString. Si utilizo @ "foo" en varios lugares, se hace referencia al mismo objeto NSString inmutable.uso de NSString estático frente a constantes NSString en línea

¿Por qué aparece este fragmento de código en cuando (por ejemplo, en UITableViewCell reutilización):

static NSString *CellId = @"CellId"; 
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellId]; 
if (cell == nil) { 
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:CellId]; 

En lugar de simplemente:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellId"]; 
if (cell == nil) { 
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:@"CellId"]; 

supongo que es para protegerme de hacer un error tipográfico en el nombre del identificador que el compilador no captaría. Pero si es así, ¿no acabo:

#define kCellId @"CellId" 

y evitar la NSString * poco estática? ¿O me estoy perdiendo algo?

+0

Esto también ** garantiza la igualdad del puntero ** que puede proporcionarle algún beneficio de rendimiento. Hasta donde yo sé, los macro símbolos no tienen la garantía. – Eonil

Respuesta

57

es una buena práctica para encender literales en constantes debido a que:

  1. Ayuda a evitar errores tipográficos, como usted ha dicho
  2. Si desea cambiar la constante, es suficiente para cambiarlo en un solo lugar

yo prefiero usar static const NSString* static NSString* const porque es un poco más seguro que #define. Tiendo a evitar el preprocesador a menos que realmente lo necesite.

+18

Y las constantes de cadena se pueden examinar fácilmente en gdb. #define es un verdadero dolor. Pero tu uso de const aquí es incorrecto. Tiene que ser "static NSString * const". Su orden de const no logra realmente nada útil en objc. Intenta reasignar tu variable de cadena hecha de esta manera en lugar de hacerlo a mi manera y verás que en un caso obtienes un error de compilación y el otro no. –

+0

En realidad no está evitando el preprocesador. Todas las @ sigils son en realidad directivas de preprocesador. – uchuugaka

+3

@uchuugaka Tal vez por "evitar el preprocesador" quiso decir "evite confiar en el reemplazo macro del preprocesador (es decir,' # define') y todos los posibles problemas que puedan implicar ". –

3

No se garantiza que al usar @"foo" en múltiples lugares, el tiempo de ejecución use el mismo almacenamiento para ellos, y ciertamente no puede ser el caso en la unidad de compilación o los límites de la biblioteca.
Prefiero usar static NSString *string = @"foo", especialmente con muchas cadenas literales.

8

Debe hacer la variable estática const.

Una diferencia entre la variable estática y una macro es que las macros no funcionan bien con los depuradores. Las macros tampoco son tipo seguras.

Gran parte de los consejos static-var-vs-macro para C y C++ se aplica a Obj-C.

+0

Gracias por las referencias, no las había visto. – sickp

+0

Buscar SO (a través de Google) para '' static const "macro' para obtener más información. – outis

2

Supongo que es para protegerme de hacer un error tipográfico en el nombre del identificador que el compilador no capte.

Correcto. Es solo práctica básica de programación defensiva. El resultado compilado (con suerte) es el mismo de cualquier manera.

pero si es así, podría no acabo:

#define kCellId @"CellId" 

y evitar la NSString * poco estática? ¿O me estoy perdiendo algo?

Sí. Pero el símbolo kCellId se definiría globalmente, al menos en su unidad de compilación. La declaración de una variable estática hace que el símbolo sea local para ese bloque.

Normalmente verá las constantes de cadena definidas como variables globales o variables estáticas en lugar de definir el preprocesador. Esto ayuda a garantizar que solo se trata de una única instancia de cadena entre diferentes unidades de compilación.

36

Me encanta todas las respuestas aquí sin un ejemplo sencillo de cómo declarar correctamente uno ... para ...

Si desea que la constante de estar visible externamente (es decir. "Global") ... . declararlo como tal en una cabecera ...

extern NSString *const MyTypoProneString;

y definir en un archivo .m, FUERA cualquier @implementation como ...

NSString * const MyTypoProneString = @"iDoNtKnOwHoW2tYpE";

Dicho esto ... si simplemente desea una static const que es local a su implementación de la clase (o incluso un cierto método!) ... simplemente declarar la cadena DENTRO la implementación (o método) como ...

static NSString *MavisBeacon = @"She's a freakin' idiot";

EDITAR Aunque muestro cómo hacer esto ... todavía tengo estar convencidos de que este estilo es de ninguna manera mejor que el, más simple y menos repetitivas Declaración única ridículamente corto, al estilo de ..

#define SomeStupidString @"DefiningConstantsTwiceIsForIdiots" 

Usa #define 's son mucho menos molestos ... Solo que no permitas que el preprocesador-jugador-enemigo te deprima.

+6

Un poco viejo, pero en realidad hay una razón realmente buena para no usar #define - #define macros son básicamente reemplazos, por lo que cada vez que llame a SomeStupidString en el código, el preprocesador reemplaza eso con un * new * literal de cadena. El uso de const externo/estático apunta todas las referencias a un solo lugar en la memoria. Esto es * mucho * más eficiente y eficiente en la memoria. –

+0

Es bueno saber ... Desearía poder descifrar cómo crearlos _en masa_, con una macro variada, _o algo_, aunque ... Todavía tengo que encontrar una buena manera de "sacarlos", y menos aún no tenerlos para dividir la declaración + la implementación en DOS archivos (gimoteo, sollozos) ... –

+2

El comentario de Matt S. en realidad no es correcto. Los literales de cadena idénticos, en cualquier lugar dentro de una aplicación, apuntan al mismo objeto. Crea dos literales NSString e inspecciona sus punteros. Parece que, incluso en RELEASE, son el mismo objeto. –

1

Por lo tanto, estoy entrando en esto un poco tarde, pero esto se ha preguntado muchas veces de varias maneras en las áreas C/C++ de SO, pero básicamente aquí hay una versión ampliada de mi comentario a alex gray:

Cada vez que piense que debería usar un #define para macros de cadena, lo más probable es que no deba hacerlo. La razón es porque las macros #define son básicamente reemplazos de expresiones regulares para el preprocesador. Cada vez que el preprocesador ve una macro llamada, la reemplaza con lo que sea que haya definido. Esto significa que una nueva cadena literal cada vez se asignará a la memoria, lo que es realmente malo en lugares como identificadores de reutilización de celda (por lo que el código de UITableViewController de Apple usa una estática).

El uso de const externo/estático apunta todas las referencias a un solo lugar en la memoria, como mencionó Eonil. Esto es mucho más eficiente y eficiente en la memoria, lo cual es muy importante en los dispositivos móviles.