¿Qué es una enumeración typedef en Objective-C?

1087

No creo que entienda fundamentalmente qué enumes un y cuándo usarlo.

Por ejemplo:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

¿Qué se declara realmente aquí?

Craig
fuente
2
¿El tipo definido por el usuario se llama "enum"? Eso es lo que había pensado, hasta que encontré un código que tenía múltiples declaraciones typedef enum.
Craig
8
No, el tipo definido por el usuario es ShapeType. Lea sobre typedef: en.wikipedia.org/wiki/Typedef
rampion
66
Un typedef en Objective-C es exactamente igual a typedef en C. Y una enumeración en Objective-C es exactamente igual a una enumeración en C. Esto declara una enumeración con tres constantes kCircle = 0, kRectangle = 1 y kOblateSpheroid = 2, y le da al tipo de enumeración el nombre ShapeType. Si no sabe lo que significa "typedef" y "enum", compre un libro sobre C.
gnasher729

Respuestas:

1565

Hay tres cosas que les está declarando aquí: un tipo enumerado en el anonimato se declara, ShapeTypese desea declarar un typedef para que la enumeración anónima, y los tres nombres kCircle, kRectangley kOblateSpheroidse declaran como constantes integrales.

Analicemos eso. En el caso más simple, una enumeración puede declararse como

enum tagname { ... };

Esto declara una enumeración con la etiqueta tagname. En C y Objective-C (pero no en C ++), cualquier referencia a esto debe ir precedida de la enumpalabra clave. Por ejemplo:

enum tagname x;  // declare x of type 'enum tagname'
tagname x;  // ERROR in C/Objective-C, OK in C++

Para evitar tener que usar la enumpalabra clave en todas partes, se puede crear un typedef:

enum tagname { ... };
typedef enum tagname tagname;  // declare 'tagname' as a typedef for 'enum tagname'

Esto se puede simplificar en una línea:

typedef enum tagname { ... } tagname;  // declare both 'enum tagname' and 'tagname'

Y finalmente, si no necesitamos poder usar enum tagnamela enumpalabra clave, podemos hacer el enumanónimo y solo declararlo con el nombre typedef:

typedef enum { ... } tagname;

Ahora, en este caso, estamos declarando ShapeTypeser un nombre definido por tipo de una enumeración anónima. ShapeTypees en realidad un tipo entero, y sólo debe utilizarse para declarar variables que mantienen uno de los valores que figuran en la declaración (es decir, uno de kCircle, kRectangley kOblateSpheroid). Sin ShapeTypeembargo, puede asignar un valor a una variable mediante conversión, por lo que debe tener cuidado al leer valores de enumeración.

Finalmente, kCircle, kRectangle, y kOblateSpheroidse declaran como constantes integrales en el espacio de nombres global. Como no se especificaron valores específicos, se asignan a enteros consecutivos que comienzan con 0, por lo que kCirclees 0, kRectanglees 1 y kOblateSpheroides 2.

Adam Rosenfield
fuente
66
Buena explicación: solo para agregar una cosa, las estructuras siguen reglas de nomenclatura similares en C (no estoy seguro acerca de Objective-C).
Michael Burr
109
Objective-C es un superconjunto apropiado de C. Todas las reglas de nomenclatura de C struct en C son igual de válidas en Objective-C.
sigjuice 01 de
Increíble. ¿Puedo usar la enumeración de estilo C ++ y tampoco necesito escribir enumeración :)
user4951
11
Puede usar enumeraciones de estilo C ++ si el archivo en el que las declara es un archivo .mm en lugar de un .m. Objective-C ++ es absurdamente poderoso.
Kevin Hoffman
14
Y una vez que haya entendido esta respuesta, vale la pena mirar los nuevos NS_ENUM y NS_OPTIONS. Tutorial aquí: nshipster.com/ns_enum-ns_options y SO aquí: stackoverflow.com/questions/14080750/…
Snowcrash
254

Apple recomienda definir enumeraciones como esta desde Xcode 4.4 :

typedef enum ShapeType : NSUInteger {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

También proporcionan una práctica macro NS_ENUM:

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

Estas definiciones proporcionan una verificación de tipo más fuerte y una mejor finalización del código. No pude encontrar la documentación oficial de NS_ENUM, pero puedes ver el video "Modern Objective-C" de la sesión de WWDC 2012 aquí .


ACTUALIZACIÓN
Enlace a la documentación oficial aquí .

Vladimir Grigorov
fuente
13
La parte sobre "Mejoras Enum" comienza a las 5:58
vikingosegundo
55
Como se comentó en otra respuesta, vea la explicación de la NS_ENUMmacro de Apple por NSHipster: NSHipster.com/ns_enum-ns_options
Basil Bourque
1
Este es el enlace a la documentación oficial sobre NS_ENUM: developer.apple.com/library/ios/releasenotes/ObjectiveC/…
YoGiN
50

Una enumeración declara un conjunto de valores ordenados; el typedef simplemente agrega un nombre útil a esto. El primer elemento es 0, etc.

typedef enum {
Monday=1,
...
} WORKDAYS;

WORKDAYS today = Monday;

Lo anterior es solo una enumeración de las etiquetas shapeType.

hburde
fuente
34

Un tipo definido por el usuario que tiene los posibles valores de kCircle, kRectangleo kOblateSpheroid. Sin embargo, los valores dentro de la enumeración (kCircle, etc.) son visibles fuera de la enumeración. Es importante tener eso en cuenta ( int i = kCircle;es válido, por ejemplo).

Brian Mitchell
fuente
30

Actualización para el cambio de 64 bits: según los documentos de Apple sobre los cambios de 64 bits,

Las enumeraciones también se escriben: en el compilador LLVM, los tipos enumerados pueden definir el tamaño de la enumeración. Esto significa que algunos tipos enumerados también pueden tener un tamaño que es más grande de lo esperado. La solución, como en todos los demás casos, es no hacer suposiciones sobre el tamaño de un tipo de datos. En su lugar, asigne cualquier valor enumerado a una variable con el tipo de datos adecuado

Por lo tanto, debe crear una enumeración con el tipo de sintaxis a continuación si admite 64 bits.

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

o

typedef enum ShapeType : NSUInteger {
   kCircle,
   kRectangle,
   kOblateSpheroid
} ShapeType;

De lo contrario, dará lugar a advertencia como Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

Actualización para programación rápida:

En Swift, hay un cambio de sintaxis.

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }
Mani
fuente
Si necesita reenviar declarar enumeración (NS_ENUM): stackoverflow.com/a/42009056/342794
lal
25

La enumeración (abreviatura de enumeración) se utiliza para enumerar un conjunto de valores (enumeradores). Un valor es una cosa abstracta representada por un símbolo (una palabra). Por ejemplo, una enumeración básica podría ser

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };

Esta enumeración se llama anónima porque no tiene un símbolo para nombrarla. Pero sigue siendo perfectamente correcto. Solo úsalo así

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;

Okay. La vida es bella y todo va bien. Pero un día necesita reutilizar esta enumeración para definir una nueva variable para almacenar myGrandFatherPantSize, luego escribe:

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;

Pero entonces tiene un error de compilación "redefinición de enumerador". En realidad, el problema es que el compilador no está seguro de que primero enumere y que en segundo lugar describa lo mismo.

Luego, si desea reutilizar el mismo conjunto de enumeradores (aquí xs ... xxxxl) en varios lugares, debe etiquetarlo con un nombre único. La segunda vez que use este conjunto, solo tiene que usar la etiqueta. Pero no olvide que esta etiqueta no reemplaza la palabra enum, sino solo el conjunto de enumeradores. Luego tenga cuidado de usar enum como de costumbre. Me gusta esto:

// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize; 
// here the second use of my enum. It works now!
enum sizes myGrandFatherPantSize;

también puede usarlo en una definición de parámetro:

// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;

Se podría decir que reescribir la enumeración en todas partes no es conveniente y hace que el código se vea un poco extraño. Tienes razón. Un tipo real sería mejor.

Este es el paso final de nuestra gran progresión hacia la cumbre. Simplemente agregando un typedef, transformemos nuestra enumeración en un tipo real. Oh, lo último, typedef no está permitido dentro de tu clase. Luego defina su tipo justo arriba. Hazlo asi:

// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type

@interface myClass {
   ...
   size_type myGrandMotherDressSize, myGrandFatherPantSize;
   ...
}

Recuerda que la etiqueta es opcional. Entonces, desde aquí, en ese caso, no etiquetamos los enumeradores, sino solo para definir un nuevo tipo. Entonces ya no lo necesitamos más.

// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;

@interface myClass : NSObject {
  ...
  size_type myGrandMotherDressSize, myGrandFatherPantSize;
  ...
}
@end

Si está desarrollando en Objective-C con XCode, le dejo descubrir algunas buenas macros con el prefijo NS_ENUM. Eso debería ayudarlo a definir buenas enumeraciones fácilmente y, además, ayudará al analizador estático a realizar algunas comprobaciones interesantes antes de compilar.

Buena enum!

Vincent Zgueb
fuente
Siempre pensé "por qué alguien respondería una pregunta que ya está respondida y aceptada". Chico, me equivoqué todo el tiempo! ¡Esta es la mejor respuesta y ayuda a principiantes como yo!
rak appdev
10

typedefes útil para redefinir el nombre de un tipo de variable existente. Proporciona una forma breve y significativa de llamar a un tipo de datos. p.ej:

typedef unsigned long int TWOWORDS;

aquí, el tipo unsigned long int se redefine para ser del tipo TWOWORDS. Por lo tanto, ahora podemos declarar variables de tipo unsigned long int escribiendo,

TWOWORDS var1, var2;

en vez de

unsigned long int var1, var2;
Rajneesh071
fuente
7
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

entonces puedes usarlo como: -

 ShapeType shape;

y

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

ahora puedes usarlo como: -

enum ShapeType shape;
Vivek Sehrawat
fuente
3

enum se usa para asignar valor a elementos enum que no se pueden hacer en struct. Entonces, en lugar de acceder a la variable completa, podemos hacerlo por el valor que asignamos a las variables enum. Por defecto, comienza con la asignación 0, pero podemos asignarle cualquier valor y la siguiente variable en enum se le asignará un valor al valor anterior +1.

Priyanka Naik
fuente
3

Puede usar en el siguiente formato, valor predeterminado sin formato a partir de 0, así

  • kCircle es 0,
  • kRectángulo es 1,
  • kOblateSpheroid es 2.

Puede asignar su propio valor de inicio específico.

typedef enum : NSUInteger {
    kCircle, // for your value; kCircle = 5, ...
    kRectangle,
    kOblateSpheroid
} ShapeType;

ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0
Bilal Arslan
fuente
2

Un typedef le permite al programador definir un tipo Objective-C como otro. Por ejemplo,

typedef int Counter; define el tipo Counter para que sea equivalente al tipo int. Esto mejora drásticamente la legibilidad del código.


fuente
2

Typedef es una palabra clave en C y C ++. Se utiliza para crear nuevos nombres para los tipos de datos básicos (char, int, float, double, struct & enum) .

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Aquí crea el tipo de datos enumerados ShapeType y podemos escribir nuevos nombres para el tipo de enumeración ShapeType como se indica a continuación

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;
Yogeesh HT
fuente
1

enum puede reducir muchos tipos de "errores" y hacer que el código sea más manejable

#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER

La definición no tiene restricciones. Es simplemente una sustitución. No puede limitar todas las condiciones del estado. Cuando el ESTADO se asigna a 5, el programa se equivocará porque no hay un estado coincidente. Pero el compilador no va a advertir ESTADO = 5

Entonces es mejor usarlo así

typedef enum SampleState {
    SampleStateGood  = 0,
    SampleStateBad,
    SampleStateOther
} SampleState;

SampleState state = SampleStateGood;
Marcus Thornton
fuente