2009-06-03 7 views
47

Tengo problemas con la visibilidad enum en un programa Objective-C. Tengo dos archivos de encabezado, y uno define un typedef enum. Otro archivo necesita usar el tipo typedef 'd.Reenviar-declare enum en Objective-C

En C recta, yo simplemente #include otro archivo de cabecera, pero en Objective-C, se recomienda no utilizar #import entre los archivos de cabecera, en lugar utilizando adelante @class declaraciones según sea necesario. Sin embargo, no puedo entender cómo reenviar-declarar un tipo de enumeración.

No necesito los valores enumerados reales, excepto en el archivo de implementación .m correspondiente, donde puedo #import de forma segura. Entonces, ¿cómo puedo obtener el typedef enum para ser reconocido en el encabezado?

+0

Por toda respuesta reciente (Swift 3, 2017) buscar en mi respuesta. http://stackoverflow.com/a/42009056/342794 – lal

Respuesta

18

Adelante y usa #import. La única razón por la que la gente recomienda usar @class cuando es posible es porque hace que su código sea un poco más rápido de compilar. Sin embargo, no hay problema con #import ing un archivo .h de otro. De hecho, debe hacer esto cuando amplíe otra clase.

+1

¿Hay alguna manera de que lo anterior sea posible, sin usar # import? ¿Qué tal simplemente hacer un 'typedef int EnumName'? –

+1

No lo creo. Vea el enlace en la respuesta de gs: http://stackoverflow.com/questions/71416/forward-declaring-an-enum-in-c –

+0

Con #import la compilación necesita minutos, y hay algo de cableado de todos modos. –

0

Debería tener #import de todos modos o crear un archivo de encabezado separado que contenga solo el typedef. No importar archivos de encabezado en un encabezado hace que la compilación sea más rápida, pero no cambia nada más.

Why doesn't C++ support forward declaration of enums?

16

La respuesta a su pregunta es que cualquiera que adelante e importar el archivo de cabecera typedef o de utilizar un tipo genérico como NSInteger en lugar del tipo de enumeración.

Sin embargo, hay más razones para no importar un archivo de encabezado que simplemente compilar la velocidad.

No importar un archivo de encabezado también reduce el acceso inadvertido a clases extrañas.

Por ejemplo, supongamos que tiene una clase TrackFileChanges que realiza un seguimiento del sistema de archivos para ver los cambios en un archivo específico, y tiene una clase CachedFile que almacena datos en caché de un archivo. Este último podría usar un ivar de tipo privado TrackFileChanges *, pero para los usos de CachedFile, esto es simplemente un detalle de implementación (idealmente, el ivar se generaría automáticamente con una propiedad privada usando el nuevo tiempo de ejecución, pero eso no es posible si tú ' re usando el tiempo de ejecución anterior).

Por lo tanto, los clientes que #import "CachedFile.h" probablemente no necesiten o no quieran tener acceso a TrackFileChanges.h. Y si lo hacen, deben dejarlo en claro al #importarlo ellos mismos. Al usar @class TrackFileChanges instea de #import "TrackFileChanges.h" en CachedFile.h, mejora la encapsulación.

Pero dicho todo esto, no hay nada malo en importar un archivo de cabecera desde un segundo archivo de cabecera si el segundo encabezado desea exponer el primero a todos los clientes. Por ejemplo, los archivos de encabezado que declaran clases deben importarse directamente en los archivos de cabecera de subclases, y los archivos de cabecera que declaran protocolos bien pueden importarse directamente (aunque usted puede usar @protocol ABC; para evitar esto).

4

Si estás bien usando extensiones del compilador, podría utilizar este orden en Clang:

enum Enum; 
typedef enum Enum Enum2; 

void f(Enum2); // ok. it sees this type's true name. 

enum Enum { 
    E_1 
}; 

// ok. now its declaration is visible and we can use it. 

void f(Enum2 e) { 

} 

Nota: Se disparará una advertencia -Wpedantic.


Si está utilizando C++ 11, debe usar sus enumeraciones, que son seguras para reenviar declarar - p. enum class Enum:uint8_t; (no es una extensión del compilador).

+1

Puede simplificar esta respuesta a esto: 'typedef enum Enum Enum;' Luego simplemente use Enum en la definición y declaración de su método. –

15

más reciente forma (Swift 3; de mayo de 2017) para reenviar declarar la enumeración (NS_ENUM/NS_OPTION) en Objective-C es el uso de lo siguiente:

// Forward declaration for XYZCharacterType in other header say XYZCharacter.h 
typedef NS_ENUM(NSUInteger, XYZCharacterType); 


// Enum declaration header: "XYZEnumType.h" 
#ifndef XYZCharacterType_h 
#define XYZCharacterType_h 

typedef NS_ENUM(NSUInteger, XYZEnumType) { 
    XYZCharacterTypeNotSet, 
    XYZCharacterTypeAgent, 
    XYZCharacterTypeKiller, 
}; 

#endif /* XYZCharacterType_h */` 
+1

funcionó para mí con swift 3 – stringRay2014

+3

Hoy en día esa debería ser la respuesta aceptada – citxx

+1

Empecé a mirar typedef NS_ENUM ayer como una forma de limpiar el antiguo código de Objective C - y esta respuesta funcionó para mí. – Greg

Cuestiones relacionadas