Forward-declare enum in Objective-C


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

En straight C, simplemente #include el otro archivo de encabezado, pero en Objective-C, se recomienda no usar #import entre archivos de encabezado, en lugar de usar declaraciones forward @class según sea necesario. Sin embargo, no puedo averiguar 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 evitar con seguridad #import. Entonces, ¿cómo puedo obtener el typedef enum para ser reconocido en el encabezado?

Author: Stephen Touset, 2009-06-03

6 answers

Sigue adelante y usa #import. La única razón por la que la gente recomienda usar @class cuando sea posible es porque hace que su código sea un poco más rápido de compilar. Sin embargo, no hay ningún problema con #importing one .archivo h de otro. De hecho, necesitas hacer esto al extender otra clase.

 16
Author: Sebastian Celis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-03 18:56:47

La forma más reciente (Swift 3; mayo de 2017) de reenviar la declaración de la enumeración (NS_ENUM/NS_OPTION) en objective-c es usar 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 */`
 26
Author: lal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-03 19:50:24

La respuesta a su pregunta es importar el archivo de encabezado typedef o usar un tipo genérico como NSInteger en lugar del tipo enum.

Sin embargo, hay más razones para no importar un archivo de encabezado que solo la velocidad de compilación.

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 rastrea el sistema de archivos para 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 privado de tipo 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 utilizando el nuevo tiempo de ejecución, pero eso no es posible si está utilizando el tiempo de ejecución anterior).

Entonces clientes que #importan "CachedFile.h " probablemente no necesitan o quieren acceso a TrackFileChanges.h. Y si lo hacen, deben dejarlo claro por # importarlo ellos mismos. Usando @ class TrackFileChanges instea de # import " TrackFileChanges.h " en CachedFile.h mejora la encapsulación.

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

 15
Author: Peter N Lewis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-04 03:17:52

Si estás bien usando extensiones de compilador, puedes usar 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: Activará una advertencia -Wpedantic.


Si está utilizando C++11, debe usar sus enumeraciones, que son seguras para reenviar declaraciones {por ejemplo, enum class Enum:uint8_t; (no una extensión de compilador).

 4
Author: justin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-08 01:33:38

Lo que funcionó para una declaración hacia adelante de una enumeración para mí en un Objetivo C.el archivo h estaba en el nombre del proyecto-Swift.h archivo y ver lo que puso, que resultó ser el siguiente:

Enum SwiftEnumName: NSInteger;

Necesitaba esta declaración forward porque tenía un tipo de parámetro de función SwiftEnumName. Y no me dejaba poner el nombre del proyecto-Swift.h importación en el objetivo C.archivo h.

Entonces en el Objetivo C.m archivo Acabo de tener el # import "ProjectName-Swift.h " en él y acaba de utilizar el SwiftEnum normalmente.

Esto estaba usando Swift 4.1.2.

 0
Author: Doug Voss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-17 19:34:13

Tendría que #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.

¿Por qué C++ no admite la declaración directa de enumeraciones?

 -2
Author: Georg Schölly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:47:05