Qu'est-ce qu'une énumération typedef dans Objective-C?

1087

Je ne pense pas que je comprends fondamentalement ce qu'est un enum, et quand l'utiliser.

Par exemple:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Qu'est-ce qui est vraiment déclaré ici?

Craig
la source
2
Le type défini par l'utilisateur est-il appelé "énumération"? C'est ce que j'avais pensé, jusqu'à ce que je tombe sur du code qui avait plusieurs déclarations d'énumération typedef.
Craig
8
Non, le type défini par l'utilisateur est ShapeType. Pour en savoir plus sur typedef: en.wikipedia.org/wiki/Typedef
rampion
6
Un typedef dans Objective-C est exactement le même qu'un typedef dans C. Et une énumération dans Objective-C est exactement la même chose qu'une énumération dans C. Ceci déclare une énumération avec trois constantes kCircle = 0, kRectangle = 1 et kOblateSpheroid = 2, et donne au type enum le nom ShapeType. Si vous ne savez pas ce que "typedef" et "enum" signifient, achetez un livre sur C.
gnasher729

Réponses:

1565

Trois choses sont déclarées ici: un type anonyme est recensée déclaré, ShapeTypeest d' être déclaré typedef pour cette énumération anonyme, et les trois noms kCircle, kRectangleet kOblateSpheroidsont déclarées comme constantes intégrales.

Décomposons cela. Dans le cas le plus simple, une énumération peut être déclarée comme

enum tagname { ... };

Cela déclare une énumération avec la balise tagname. En C et Objective-C (mais pas C ++), toute référence à cela doit être précédée du enummot - clé. Par exemple:

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

Afin d'éviter d'avoir à utiliser le enummot - clé partout, un typedef peut être créé:

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

Cela peut être simplifié en une seule ligne:

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

Et enfin, si nous n'avons pas besoin de pouvoir l'utiliser enum tagnameavec le enummot - clé, nous pouvons faire l' enumanonymat et le déclarer uniquement avec le nom typedef:

typedef enum { ... } tagname;

Maintenant, dans ce cas, nous ShapeTypedéclarons être le nom typé d'une énumération anonyme. ShapeTypeest vraiment juste un type intégral, et ne doit être utilisé pour déclarer des variables qui détiennent l' une des valeurs énumérées dans la déclaration (qui est, l' un des kCircle, kRectangleet kOblateSpheroid). Vous pouvez cependant attribuer une ShapeTypevariable à une variable en effectuant un cast, vous devez donc être prudent lors de la lecture des valeurs d'énumération.

Enfin, kCircle, kRectangleet kOblateSpheroidsont déclarées comme constantes intégrées dans l'espace de noms global. Puisqu'aucune valeur spécifique n'a été spécifiée, elles sont affectées à des entiers consécutifs commençant par 0, donc kCircle0, kRectangle1 et kOblateSpheroid2.

Adam Rosenfield
la source
6
Belle explication - juste pour ajouter une chose, les structures suivent des règles de dénomination similaires en C (pas sûr d'Objective-C).
Michael Burr
109
Objective-C est un sur-ensemble approprié de C. Toutes les règles de dénomination de structure C en C sont tout aussi valides en Objective-C.
sigjuice
Impressionnant. Puis-je simplement utiliser l'énumération de style C ++ et je n'ai pas besoin d'écrire l'énumération :)
user4951
11
Vous pouvez utiliser des énumérations de style C ++ si le fichier dans lequel vous les déclarez est un fichier .mm plutôt qu'un .m. Objective-C ++ est absurdement puissant.
Kevin Hoffman
14
Et une fois que vous aurez compris cette réponse, cela vaut la peine d'examiner les nouveaux NS_ENUM et NS_OPTIONS. Tutoriel ici: nshipster.com/ns_enum-ns_options et SO ici: stackoverflow.com/questions/14080750/…
Snowcrash
254

Apple recommande de définir des énumérations comme celle-ci depuis Xcode 4.4 :

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

Ils fournissent également une macro pratique NS_ENUM:

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

Ces définitions fournissent une vérification de type plus forte et une meilleure exécution du code. Je n'ai pas pu trouver la documentation officielle de NS_ENUM, mais vous pouvez regarder la vidéo "Modern Objective-C" de la session WWDC 2012 ici .


UPDATE
Lien vers la documentation officielle ici .

Vladimir Grigorov
la source
13
La partie sur "Enum Improvements" commence à 5:58
vikingosegundo
5
Comme commenté sur une autre réponse, voir l'explication de la NS_ENUMmacro d'Apple par NSHipster: NSHipster.com/ns_enum-ns_options
Basil Bourque
1
Ceci est le lien vers la documentation officielle sur NS_ENUM: developer.apple.com/library/ios/releasenotes/ObjectiveC/…
YoGiN
50

Une énumération déclare un ensemble de valeurs ordonnées - le typedef ajoute simplement un nom pratique à cela. Le 1er élément est 0 etc.

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

WORKDAYS today = Monday;

Ce qui précède n'est qu'une énumération des balises shapeType.

hburde
la source
34

Un utilisateur type défini qui a les valeurs possibles kCircle, kRectangleou kOblateSpheroid. Les valeurs à l'intérieur de l'énumération (kCircle, etc.) sont cependant visibles à l'extérieur de l'énumération. Il est important de garder cela à l'esprit ( int i = kCircle;est valable, par exemple).

Brian Mitchell
la source
30

Mise à jour pour la modification 64 bits: selon les documents Apple concernant les modifications 64 bits,

Les énumérations sont également typées: dans le compilateur LLVM, les types énumérés peuvent définir la taille de l'énumération. Cela signifie que certains types énumérés peuvent également avoir une taille supérieure à ce que vous attendez. La solution, comme dans tous les autres cas, est de ne faire aucune hypothèse sur la taille d'un type de données. Au lieu de cela, affectez toutes les valeurs énumérées à une variable avec le type de données approprié

Vous devez donc créer une énumération avec le type comme syntaxe ci-dessous si vous prenez en charge 64 bits.

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

ou

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

Sinon, cela conduira à un avertissement Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

Mise à jour pour la programmation rapide:

Dans swift, il y a un changement de syntaxe.

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }
Mani
la source
Si besoin de transmettre déclarer l'énumération (NS_ENUM): stackoverflow.com/a/42009056/342794
lal
25

L'énumération (abréviation d'énumération) est utilisée pour énumérer un ensemble de valeurs (énumérateurs). Une valeur est une chose abstraite représentée par un symbole (un mot). Par exemple, une énumération de base peut être

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

Cette énumération est appelée anonyme car vous n'avez pas de symbole pour la nommer. Mais c'est toujours parfaitement correct. Il suffit de l'utiliser comme ça

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

D'accord. La vie est belle et tout se passe bien. Mais un jour, vous devez réutiliser cette énumération pour définir une nouvelle variable pour stocker myGrandFatherPantSize, puis vous écrivez:

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

Mais alors vous avez une erreur de compilation "redéfinition de l'énumérateur". En fait, le problème est que le compilateur n'est pas sûr que vous énumérez d'abord et que vous décrivez ensuite la même chose.

Ensuite, si vous souhaitez réutiliser le même ensemble d'énumérateurs (ici xs ... xxxxl) à plusieurs endroits, vous devez le marquer avec un nom unique. La deuxième fois que vous utilisez cet ensemble, vous n'avez qu'à utiliser la balise. Mais n'oubliez pas que cette balise ne remplace pas le mot enum mais juste l'ensemble des énumérateurs. Veillez ensuite à utiliser enum comme d'habitude. Comme ça:

// 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;

vous pouvez également l'utiliser dans une définition de paramètre:

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

On pourrait dire que réécrire enum partout n'est pas pratique et rend le code un peu étrange. Tu as raison. Un vrai type serait mieux.

Il s'agit de l'ultime étape de notre grande progression vers le sommet. En ajoutant simplement un typedef, transformons notre énumération en un vrai type. Oh la dernière chose, typedef n'est pas autorisé dans votre classe. Définissez ensuite votre type juste au-dessus. Fais-le comme ça:

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

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

N'oubliez pas que la balise est facultative. Alors qu'ici, dans ce cas, nous ne marquons pas les énumérateurs mais juste pour définir un nouveau type. Ensuite, nous n'en avons plus vraiment besoin.

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

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

Si vous développez en Objective-C avec XCode, je vous laisse découvrir de belles macros préfixées avec NS_ENUM. Cela devrait vous aider à définir facilement de bonnes énumérations et aidera l'analyseur statique à effectuer des vérifications intéressantes pour vous avant de compiler.

Bon Enum!

Vincent Zgueb
la source
J'ai toujours pensé "pourquoi quelqu'un répondrait-il à une question à laquelle on a déjà répondu et accepté". Mon garçon, je me trompais tout le temps! Ceci est la meilleure réponse et aide les débutants comme moi!
rak appdev
10

typedefest utile pour redéfinir le nom d'un type de variable existant. Il fournit un moyen court et significatif d'appeler un type de données. par exemple:

typedef unsigned long int TWOWORDS;

ici, le type unsigned long int est redéfini pour être du type TWOWORDS. Ainsi, nous pouvons maintenant déclarer des variables de type non signé long int en écrivant,

TWOWORDS var1, var2;

au lieu de

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

alors vous pouvez l'utiliser comme: -

 ShapeType shape;

et

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

maintenant vous pouvez l'utiliser comme: -

enum ShapeType shape;
Vivek Sehrawat
la source
3

enum est utilisé pour assigner une valeur aux éléments enum qui ne peuvent pas être faits dans struct. Donc, à chaque fois au lieu d'accéder à la variable complète, nous pouvons le faire par la valeur que nous attribuons aux variables enum. Par défaut, il commence par une affectation de 0, mais nous pouvons lui attribuer n'importe quelle valeur et la variable suivante enum recevra une valeur la valeur précédente +1.

Priyanka Naik
la source
3

Vous pouvez utiliser dans le format ci-dessous, la valeur par défaut brute à partir de 0, donc

  • kCircle vaut 0,
  • kRectangle vaut 1,
  • kOblateSpheroid est 2.

Vous pouvez attribuer votre propre valeur de départ spécifique.

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

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

Un typedef permet au programmeur de définir un type Objective-C comme un autre. Par exemple,

typedef int Counter; définit le type Counter comme équivalent au type int. Cela améliore considérablement la lisibilité du code.


la source
2

Le Typedef est un mot-clé en C et C ++. Il est utilisé pour créer de nouveaux noms pour les types de données de base (char, int, float, double, struct & enum) .

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Ici, il crée le type de données énuméré ShapeType et nous pouvons écrire de nouveaux noms pour le type enum ShapeType comme indiqué ci-dessous

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;
Yogeesh HT
la source
1

enum peut réduire de nombreux types d'erreurs et rendre le code plus facile à gérer

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

La définition n'a pas de contraintes. C'est simplement une substitution. Il n'est pas en mesure de limiter toutes les conditions de l'État. Lorsque l'état est affecté à 5, le programme sera erroné, car il n'y a pas d'état correspondant. Mais le compilateur ne va pas avertir STATE = 5

Il vaut donc mieux utiliser comme ça

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

SampleState state = SampleStateGood;
Marcus Thornton
la source