¿Cuál es la mejor manera de crear constantes en Objective-C?

156

Estoy creando un cliente Reddit con fines de aprendizaje. Necesito tener un archivo con constantes. Estaba pensando en importar el archivo en el Reddit-Prefix.pcharchivo para que las constantes estén disponibles para todos los archivos. ¿Es una buena forma de hacer las cosas? Además, hice mi investigación y encontré varios métodos para crear constantes, pero no sé cuál usar:

  • #define macro
  • const
  • static const
  • extern const
  • enum

Entonces, ¿cuál es la forma preferida? ¿Qué es la convención? Sé que "depende", pero mi pregunta más específica es: ¿Cuáles son los casos de uso para cada una de esas soluciones?

Además, si lo uso extern const, ¿necesito importar el archivo, o las constantes estarán disponibles globalmente sin importar el archivo?

Una cosa que podría concluir lógicamente es que enumes la mejor opción al definir algo como dominios de error personalizados (¿estoy realmente en lo cierto?). ¿Pero qué hay de los demás?

Robert Audi
fuente
stackoverflow.com/questions/11153156/… visite este enlace ... su solución está en esta publicación
Usuario 1531343
3
@BhavikKama: Esa es una pregunta más estrecha que contrasta con dos soluciones específicas.
Peter Hosey
para - static const, #define, enumeración, este enlace es muy útil stackoverflow.com/questions/1674032/static-const-vs-define-in-c que proporciona una buena explicación de los 3 alternativa de const
Usuario 1531343
enumsolo es útil para valores integrales. #definey las constantes pueden ser de cualquier tipo de datos.
rmaddy
const, static consty extern constson todos iguales excepto por el alcance. Entonces, en realidad solo hay tres opciones.
rmaddy

Respuestas:

385

La primera pregunta es qué alcance desea que tengan sus constantes, que en realidad son dos preguntas:

  • ¿Estas constantes son específicas de una sola clase, o tiene sentido tenerlas en toda la aplicación?
  • Si son específicos de la clase, ¿son para uso de los clientes de la clase o solo dentro de la clase?

Si son específicos e internos de una sola clase, declare como static consten la parte superior del archivo .m, así:

static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Si pertenecen a una sola clase pero deben ser públicas / utilizadas por otras clases, declare como externen el encabezado y defínalos en el .m:

//.h
extern NSString *const MyThingNotificationKey;

//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";

Si deben ser globales, declararlos en un encabezado y definirlos en un módulo correspondiente, específicamente para esas constantes.

Puede mezclarlos y combinarlos para diferentes constantes con diferentes niveles de cuán global desea que sean, y para diferentes constantes globales que simplemente no pertenecen juntas; puede colocarlas en módulos separados, cada uno con su propio encabezado, si querer.

¿Por qué no #define?

La vieja respuesta es "las macros no tienen información de tipo", pero los compiladores de hoy en día son bastante inteligentes al hacer toda la verificación de tipo para los literales (a qué se expanden las macros) y las variables.

La respuesta moderna es porque el depurador no sabrá sobre sus macros. No se puede decir [myThing addObserver:self forKey:MyThingNotificationKey]en un comando de depurador si MyThingNotificationKeyes una macro; el depurador solo puede saberlo si es una variable.

¿Por qué no enum?

Bueno, rmaddy me ganó en los comentarios: enum solo puede definir constantes enteras. Cosas como números de identificación de serie, máscaras de bits, códigos de cuatro bytes, etc.

Para esos fines, enumes genial y absolutamente deberías usarlo. (Aún mejor, use las macros NS_ENUMyNS_OPTIONS .) Para otras cosas, debe usar otra cosa; enumno hace nada más que enteros.

Y otras preguntas

Estaba pensando en importar el archivo en el archivo Reddit-Prefix.pch para que las constantes estén disponibles para todos los archivos. ¿Es una buena forma de hacer las cosas?

Probablemente inofensivo, pero probablemente excesivo. Importe sus encabezados constantes donde los necesite.

¿Cuáles son los casos de uso para cada una de esas soluciones?

  • #define: Bastante limitado. Honestamente, no estoy seguro de que haya una buena razón para usar esto para las constantes.
  • const: Lo mejor para las constantes locales. Además, debe usar esto para uno que declaró en un encabezado y que ahora está definiendo.
  • static const: Mejor para constantes específicas de archivo (o específicas de clase).
  • extern const: Debe usar esto al exportar una constante en un encabezado.

Además, si lo uso extern const, ¿necesito importar el archivo, o las constantes estarán disponibles globalmente sin importar el archivo?

Debe importar el archivo, ya sea en cada archivo donde lo usa o en el encabezado del prefijo.

Peter Hosey
fuente
3
¿Por qué no usar static NSString *consten el .harchivo por completo?
Iulian Onofrei
3
@IulianOnofrei: Puede, si está en una aplicación y no en un marco. Si lo hace static NSString *const foo = @"foo";, su encabezado determina cuál es la cadena, y debe ser la misma en todas partes: si alguna vez cambia la cadena y las diferentes partes usan diferentes versiones del encabezado con una cadena diferente, las cadenas no coincidirán en la ejecución hora. En un marco, desea proporcionar acceso solo al símbolo y dejar que el marco sea la única fuente del verdadero valor de ese símbolo, para que todos obtengan la misma cadena desde un solo lugar. Eso es lo que externte atrapa.
Peter Hosey
Nota adicional sobre #defines: no se garantiza que tengan la misma dirección en la memoria (dependiendo de cómo se declaren, pueden asignar una nueva instancia cada vez que se usan), por lo que el uso myObject == MyDefineno siempre funcionará como se esperaba, pero lo myObject == MyStaticConstharé.
Ben Leggiero
¿Tiene sentido en ortografía como en static NSString *constlugar de static NSString const*?? ¿Alguna diferencia?
kokos8998
@ kokos8998 ¿hace alguna diferencia? Si lo hace static NSString const *es lo mismo static const NSString *y significa "un puntero (variable) a una NSString constante", lo cual es un poco inútil aquí ya que NSString ya es inmutable. Lo que solo quieres static NSString * const, que es un "puntero constante a un NSString"
David
8

FOUNDATION_EXPORT

Considere usar FOUNDATION_EXPORTun poco más de compatibilidad que externya que está definido en la base y compila a formatos compatibles para C, C ++ y Win32.

Como se define en NSObjCRuntime.h

#if defined(__cplusplus)
#define FOUNDATION_EXTERN extern "C"
#else
#define FOUNDATION_EXTERN extern
#endif

#if TARGET_OS_WIN32

    #if defined(NSBUILDINGFOUNDATION)
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllexport)
    #else
        #define FOUNDATION_EXPORT FOUNDATION_EXTERN __declspec(dllimport)
    #endif

    #define FOUNDATION_IMPORT FOUNDATION_EXTERN __declspec(dllimport)

#else
    #define FOUNDATION_EXPORT  FOUNDATION_EXTERN
    #define FOUNDATION_IMPORT FOUNDATION_EXTERN
#endif
Steve Moser
fuente