Pregunta Constantes en Objective-C


Estoy desarrollando un Cacao aplicación, y estoy usando constante NSStrings como formas de almacenar nombres clave para mis preferencias.

Entiendo que esta es una buena idea, ya que permite un fácil cambio de claves si es necesario. Además, es toda la noción de 'separar sus datos de su lógica'.

De todos modos, ¿hay una buena manera de hacer que estas constantes se definan una vez para toda la aplicación? Estoy seguro de que hay una manera fácil e inteligente, pero en este momento mis clases simplemente redefinen las que usan.


969
2018-02-11 21:52


origen


Respuestas:


Deberías crear un archivo de cabecera como

// Constants.h
FOUNDATION_EXPORT NSString *const MyFirstConstant;
FOUNDATION_EXPORT NSString *const MySecondConstant;
//etc.

(puedes usar extern en lugar de FOUNDATION_EXPORT si su código no se usará en entornos combinados de C / C ++ o en otras plataformas)

Puede incluir este archivo en cada archivo que use las constantes o en el encabezado precompilado para el proyecto.

Usted define estas constantes en un archivo .m como

// Constants.m
NSString *const MyFirstConstant = @"FirstConstant";
NSString *const MySecondConstant = @"SecondConstant";

Constants.m debe agregarse al objetivo de su aplicación / marco para que esté vinculado al producto final.

La ventaja de usar constantes de cadena en lugar de #define'd constantes es que puede probar la igualdad usando la comparación de punteros (stringInstance == MyFirstConstant) que es mucho más rápido que la comparación de cadenas ([stringInstance isEqualToString:MyFirstConstant]) (y más fácil de leer, IMO).


1236
2018-02-11 22:38



La manera más fácil:

// Prefs.h
#define PREFS_MY_CONSTANT @"prefs_my_constant"

Mejor manera:

// Prefs.h
extern NSString * const PREFS_MY_CONSTANT;

// Prefs.m
NSString * const PREFS_MY_CONSTANT = @"prefs_my_constant";

Uno de los beneficios de la segunda es que cambiar el valor de una constante no causa la reconstrucción de todo el programa.


264
2018-02-11 22:02



También hay una cosa para mencionar. Si necesita una constante no global, debe usar static palabra clave.

Ejemplo

// In your *.m file
static NSString * const kNSStringConst = @"const value";

Debido a la static palabra clave, esta const no es visible fuera del archivo.


Corrección menor por @QuinnTaylor: las variables estáticas son visibles dentro de un unidad de compilación. Por lo general, este es un archivo .m único (como en este ejemplo), pero puede morder si lo declaras en un encabezado que se incluye en otra parte, ya que obtendrás errores del enlazador luego de la compilación.


182
2018-02-12 16:28



La respuesta aceptada (y correcta) dice que "puede incluir este archivo [Constants.h] ... en el encabezado precompilado para el proyecto".

Como novato, tuve dificultades para hacer esto sin más explicaciones. He aquí cómo: en su archivo YourAppNameHere-Prefix.pch (este es el nombre predeterminado para el encabezado precompilado en Xcode), importe sus Constantes.h dentro de #ifdef __OBJC__ bloquear.

#ifdef __OBJC__
  #import <UIKit/UIKit.h>
  #import <Foundation/Foundation.h>
  #import "Constants.h"
#endif

También tenga en cuenta que los archivos Constants.h y Constants.m no deben contener absolutamente nada más que lo que se describe en la respuesta aceptada. (Sin interfaz o implementación).


117
2017-09-18 14:08



En general estoy usando el camino publicado por Barry Wark y Rahul Gupta.

Aunque, no me gusta repetir las mismas palabras en los archivos .h y .m. Tenga en cuenta que en el siguiente ejemplo, la línea es casi idéntica en ambos archivos:

// file.h
extern NSString* const MyConst;

//file.m
NSString* const MyConst = @"Lorem ipsum";

Por lo tanto, lo que me gusta hacer es usar maquinaria de preprocesador C. Déjame explicarte a través del ejemplo.

Tengo un archivo de cabecera que define la macro STR_CONST(name, value):

// StringConsts.h
#ifdef SYNTHESIZE_CONSTS
# define STR_CONST(name, value) NSString* const name = @ value
#else
# define STR_CONST(name, value) extern NSString* const name
#endif

El en mi par .h / .m donde quiero definir la constante, hago lo siguiente:

// myfile.h
#import <StringConsts.h>

STR_CONST(MyConst, "Lorem Ipsum");
STR_CONST(MyOtherConst, "Hello world");

// myfile.m
#define SYNTHESIZE_CONSTS
#import "myfile.h"

et voila, tengo toda la información sobre las constantes en el archivo .h solamente.


50
2017-12-02 21:53



Una ligera modificación de la sugerencia de @Krizz, para que funcione correctamente si el archivo de encabezado de constantes debe incluirse en el PCH, lo cual es bastante normal. Como el original se importa a PCH, no lo volverá a cargar en el .m archivo y así no obtienes símbolos y el enlazador no está contento.

Sin embargo, la siguiente modificación le permite funcionar. Es un poco intrincado, pero funciona.

Necesitarás 3 archivos, .h archivo que tiene las definiciones constantes, el .h archivo y el .m archivo, lo usaré ConstantList.h, Constants.h y Constants.m, respectivamente. los contenidos de Constants.h son simplemente:

// Constants.h
#define STR_CONST(name, value) extern NSString* const name
#include "ConstantList.h"

y el Constants.m el archivo se ve así:

// Constants.m
#ifdef STR_CONST
    #undef STR_CONST
#endif
#define STR_CONST(name, value) NSString* const name = @ value
#include "ConstantList.h"

Finalmente, el ConstantList.h archivo tiene las declaraciones reales y eso es todo:

// ConstantList.h
STR_CONST(kMyConstant, "Value");
…

Un par de cosas a anotar:

  1. Tuve que redefinir la macro en el .m archivo después  #undefing por la macro que se utilizará.

  2. También tuve que usar #include en lugar de #import para que esto funcione correctamente y evitar que el compilador vea los valores precompilados previamente.

  3. Esto requerirá una recompilación de su PCH (y probablemente de todo el proyecto) cada vez que se modifiquen los valores, que no es el caso si están separados (y duplicados) de forma normal.

Espero que sea útil para alguien.


25
2017-12-03 00:03



Yo mismo tengo un encabezado dedicado a declarar NSStrings constantes utilizados para preferencias como esta:

extern NSString * const PPRememberMusicList;
extern NSString * const PPLoadMusicAtListLoad;
extern NSString * const PPAfterPlayingMusic;
extern NSString * const PPGotoStartupAfterPlaying;

Luego los declara en el archivo .m adjunto:

NSString * const PPRememberMusicList = @"Remember Music List";
NSString * const PPLoadMusicAtListLoad = @"Load music when loading list";
NSString * const PPAfterPlayingMusic = @"After playing music";
NSString * const PPGotoStartupAfterPlaying = @"Go to startup pos. after playing";

Este enfoque me ha servido bien.

Editar: Tenga en cuenta que esto funciona mejor si las cadenas se utilizan en varios archivos. Si solo un archivo lo usa, puedes hacer #define kNSStringConstant @"Constant NSString" en el archivo .m que usa la cadena.


24
2018-01-26 23:15



// Prefs.h
extern NSString * const RAHUL;

// Prefs.m
NSString * const RAHUL = @"rahul";

14
2017-09-28 04:37



Como dijo Abizer, podrías ponerlo en el archivo PCH. Otra forma que no es tan sucia es crear un archivo de inclusión para todas sus claves y luego incluirlo en el archivo en el que está utilizando las claves, o incluirlo en el PCH. Con ellos en su propio archivo de inclusión, eso al menos le da un lugar para buscar y definir todas estas constantes.


12
2018-02-11 22:05



Si quieres algo como constantes globales; una manera rápida y sucia es poner las declaraciones constantes en el pch archivo.


11
2018-02-11 21:56