Was ist eine typedef-Aufzählung in Objective-C?

1087

Ich glaube nicht, dass ich grundlegend verstehe, was ein enumist und wann ich es verwenden soll.

Zum Beispiel:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Was wird hier wirklich deklariert?

Craig
quelle
2
Wird der benutzerdefinierte Typ "enum" genannt? Das hatte ich mir gedacht, bis ich auf Code stieß, der mehrere typedef enum-Deklarationen hatte.
Craig
8
Nein, der benutzerdefinierte Typ ist ShapeType. Lesen Sie mehr über typedef: en.wikipedia.org/wiki/Typedef
rampion
6
Ein typedef in Objective-C ist genau dasselbe wie ein typedef in C. Und eine Aufzählung in Objective-C ist genau dasselbe wie eine Aufzählung in C. Dies deklariert eine Aufzählung mit drei Konstanten kCircle = 0, kRectangle = 1 und kOblateSpheroid = 2 und gibt dem Aufzählungstyp den Namen ShapeType. Wenn Sie nicht wissen, was "typedef" und "enum" bedeuten, kaufen Sie ein Buch über C.
gnasher729

Antworten:

1565

Drei Dinge werden hier erklärt: ein anonymer Aufzählungstyp deklariert wird, ShapeTypeist für die anonyme Aufzählung ein typedef deklariert werden und die drei Namen kCircle, kRectangleund kOblateSpheroidwerden als integrale Konstanten deklariert.

Lassen Sie uns das aufschlüsseln. Im einfachsten Fall kann eine Aufzählung als deklariert werden

enum tagname { ... };

Dies deklariert eine Aufzählung mit dem Tag tagname. In C und Objective-C (aber nicht C ++), alle Verweise auf diese muss mit dem vorangestellt sein enumStichwort. Zum Beispiel:

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

Um zu vermeiden, dass das enumSchlüsselwort überall verwendet werden muss, kann ein typedef erstellt werden:

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

Dies kann in einer Zeile vereinfacht werden:

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

Und schließlich, wenn wir nicht in der Lage sein müssen, enum tagnamedas enumSchlüsselwort zu verwenden, können wir das enumanonymisieren und es nur mit dem typedef-Namen deklarieren:

typedef enum { ... } tagname;

In diesem Fall erklären wir, dass es ShapeTypesich um einen typisierten Namen einer anonymen Aufzählung handelt. ShapeTypeist wirklich nur ein integraler Typ, und nur Variablen verwendet werden soll , zu erklären , die in der Erklärung genannten einen des Wertes halten (das heißt, einer der kCircle, kRectangleund kOblateSpheroid). Sie können einer ShapeTypeVariablen jedoch einen anderen Wert zuweisen , indem Sie sie umwandeln. Daher müssen Sie beim Lesen von Aufzählungswerten vorsichtig sein.

Schließlich kCircle, kRectangleund kOblateSpheroidals integrale Konstanten im globalen Namespace deklariert. Da keine spezifischen Werte angegeben wurden, werden sie aufeinanderfolgenden Ganzzahlen zugewiesen, die mit 0 beginnen, also kCircle0, kRectangle1 und kOblateSpheroid2.

Adam Rosenfield
quelle
6
Nette Erklärung - um nur eines hinzuzufügen: Strukturen folgen ähnlichen Namensregeln in C (nicht sicher über Objective-C).
Michael Burr
109
Objective-C ist eine richtige Obermenge von C. Alle C-Struktur-Benennungsregeln in C sind in Objective-C genauso gültig.
Sigjuice
Genial. Kann ich nur eine Aufzählung im C ++ - Stil verwenden und muss auch keine Aufzählung schreiben :)
user4951
11
Sie können Aufzählungen im C ++ - Stil verwenden, wenn die Datei, in der Sie sie deklarieren, eine .mm-Datei und keine .m-Datei ist. Objective-C ++ ist absurd mächtig.
Kevin Hoffman
14
Und wenn Sie sich mit dieser Antwort vertraut gemacht haben, sollten Sie sich die neuen NS_ENUM und NS_OPTIONS ansehen. Tutorial hier: nshipster.com/ns_enum-ns_options und SO hier: stackoverflow.com/questions/14080750/...
Snowcrash
254

Apple empfiehlt, solche Aufzählungen seit Xcode 4.4 zu definieren :

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

Sie bieten auch ein praktisches Makro NS_ENUM:

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

Diese Definitionen bieten eine stärkere Typprüfung und eine bessere Code-Vervollständigung. Ich konnte keine offizielle Dokumentation finden NS_ENUM, aber Sie können das Video "Modern Objective-C" von der WWDC 2012-Sitzung hier ansehen .


UPDATE
Link zur offiziellen Dokumentation hier .

Vladimir Grigorov
quelle
13
Der Teil über "Enum Improvements" beginnt um 5:58
vikingosegundo
5
Wie zu einer anderen Antwort kommentiert, siehe Erklärung von Apples NS_ENUMMakro durch NSHipster: NSHipster.com/ns_enum-ns_options
Basil Bourque
1
Dies ist der Link zur offiziellen Dokumentation über NS_ENUM: developer.apple.com/library/ios/releasenotes/ObjectiveC/…
YoGiN
50

Eine Aufzählung deklariert eine Reihe von geordneten Werten - das typedef fügt diesem nur einen praktischen Namen hinzu. Das 1. Element ist 0 usw.

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

WORKDAYS today = Monday;

Das Obige ist nur eine Aufzählung von shapeType-Tags.

hburde
quelle
34

Ein Benutzer definierten Typ, die die möglichen Werte hat kCircle, kRectangleoder kOblateSpheroid. Die Werte innerhalb der Aufzählung (kCircle usw.) sind jedoch außerhalb der Aufzählung sichtbar. Es ist wichtig, dies zu berücksichtigen ( int i = kCircle;gilt zum Beispiel).

Brian Mitchell
quelle
30

Update für 64-Bit-Änderung: Laut Apple-Dokumenten über 64-Bit-Änderungen,

Aufzählungen werden ebenfalls eingegeben: Im LLVM-Compiler können Aufzählungstypen die Größe der Aufzählung definieren. Dies bedeutet, dass einige aufgezählte Typen möglicherweise auch eine größere Größe haben als erwartet. Die Lösung besteht, wie in allen anderen Fällen, darin, keine Annahmen über die Größe eines Datentyps zu treffen. Weisen Sie stattdessen einer Variablen mit dem richtigen Datentyp alle aufgezählten Werte zu

Sie müssen also eine Aufzählung mit dem folgenden Syntax erstellen, wenn Sie 64-Bit unterstützen.

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

oder

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

Andernfalls wird eine Warnung als angezeigt Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

Update für die schnelle Programmierung:

In Kürze gibt es eine Syntaxänderung.

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }
Mani
quelle
Wenn Sie weiterleiten müssen, deklarieren Sie die Aufzählung (NS_ENUM): stackoverflow.com/a/42009056/342794
18.
25

Die Aufzählung (Abkürzung für Aufzählung) wird verwendet, um eine Reihe von Werten (Aufzählungen) aufzulisten. Ein Wert ist eine abstrakte Sache, die durch ein Symbol (ein Wort) dargestellt wird. Zum Beispiel könnte eine Grundaufzählung sein

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

Diese Aufzählung wird anonym genannt, da Sie kein Symbol haben, um sie zu benennen. Aber es ist immer noch vollkommen richtig. Verwenden Sie es einfach so

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

OK. Das Leben ist schön und alles geht gut. Aber eines Tages müssen Sie diese Aufzählung wiederverwenden, um eine neue Variable zum Speichern von myGrandFatherPantSize zu definieren. Dann schreiben Sie:

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

Aber dann haben Sie einen Compilerfehler "Neudefinition des Enumerators". Tatsächlich besteht das Problem darin, dass der Compiler nicht sicher ist, ob Sie zuerst aufzählen und als Zweites dasselbe beschreiben.

Wenn Sie dann denselben Satz von Enumeratoren (hier xs ... xxxxl) an mehreren Stellen wiederverwenden möchten, müssen Sie ihn mit einem eindeutigen Namen versehen. Wenn Sie dieses Set zum zweiten Mal verwenden, müssen Sie nur das Tag verwenden. Vergessen Sie jedoch nicht, dass dieses Tag nicht das Enum-Wort ersetzt, sondern nur die Enumeratoren. Achten Sie dann darauf, enum wie gewohnt zu verwenden. So was:

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

Sie können es auch in einer Parameterdefinition verwenden:

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

Man könnte sagen, dass das Umschreiben von Enum überall nicht bequem ist und den Code etwas seltsam aussehen lässt. Du hast recht. Ein echter Typ wäre besser.

Dies ist der letzte Schritt unseres großen Fortschritts zum Gipfel. Durch einfaches Hinzufügen eines Typedef können wir unsere Aufzählung in einen echten Typ umwandeln. Oh das Letzte, typedef ist in deiner Klasse nicht erlaubt. Definieren Sie dann Ihren Typ direkt oben. Mach es so:

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

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

Denken Sie daran, dass das Tag optional ist. Dann kennzeichnen wir in diesem Fall die Enumeratoren nicht, sondern nur, um einen neuen Typ zu definieren. Dann brauchen wir es nicht mehr wirklich.

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

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

Wenn Sie in Objective-C mit XCode entwickeln, können Sie einige nette Makros entdecken, denen NS_ENUM vorangestellt ist. Dies sollte Ihnen helfen, gute Aufzählungen einfach zu definieren, und hilft dem statischen Analysator außerdem, einige interessante Überprüfungen für Sie durchzuführen, bevor Sie sie kompilieren.

Gute Aufzählung!

Vincent Zgueb
quelle
Ich dachte immer "warum sollte jemand eine Frage beantworten, die bereits beantwortet und akzeptiert wurde". Junge, ich habe mich die ganze Zeit geirrt! Dies ist die beste Antwort und hilft Anfängern wie mir!
Rak Appdev
10

typedefist nützlich, um den Namen eines vorhandenen Variablentyps neu zu definieren. Es bietet eine kurze und sinnvolle Möglichkeit, einen Datentyp aufzurufen. z.B:

typedef unsigned long int TWOWORDS;

Hier wird der Typ unsigned long int neu definiert, um vom Typ TWOWORDS zu sein. Somit können wir jetzt Variablen vom Typ unsigned long int deklarieren, indem wir schreiben:

TWOWORDS var1, var2;

anstatt

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

dann können Sie es verwenden wie: -

 ShapeType shape;

und

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

Jetzt können Sie es verwenden wie: -

enum ShapeType shape;
Vivek Sehrawat
quelle
3

enum wird verwendet, um enum-Elementen einen Wert zuzuweisen, was in struct nicht möglich ist. Anstatt auf die vollständige Variable zuzugreifen, können wir dies jedes Mal anhand des Werts tun, den wir den Variablen in enum zuweisen. Standardmäßig beginnt es mit der Zuweisung 0, aber wir können ihm einen beliebigen Wert zuweisen, und der nächsten Variablen in enum wird ein Wert zugewiesen, der dem vorherigen Wert +1 entspricht.

Priyanka Naik
quelle
3

Sie können im folgenden Format den Raw-Standardwert ab 0 verwenden

  • kCircle ist 0,
  • kRectangle ist 1,
  • kOblateSpheroid ist 2.

Sie können Ihren eigenen spezifischen Startwert zuweisen.

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

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

Mit einem typedef kann der Programmierer einen Objective-C-Typ als einen anderen definieren. Zum Beispiel,

typedef int Counter; Definiert den Typ Counter so, dass er dem int-Typ entspricht. Dies verbessert die Lesbarkeit des Codes drastisch.


quelle
2

Das Typedef ist ein Schlüsselwort in C und C ++. Es wird verwendet, um neue Namen für grundlegende Datentypen (char, int, float, double, struct & enum) zu erstellen .

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Hier wird der aufgezählte Datentyp ShapeType erstellt und wir können neue Namen für den Aufzählungstyp ShapeType schreiben, wie unten angegeben

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

enum kann viele Arten von "Fehlern" reduzieren und den Code übersichtlicher machen

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

Die Definition unterliegt keinen Einschränkungen. Es ist einfach nur eine Substitution. Es ist nicht in der Lage, alle Bedingungen des Staates einzuschränken. Wenn der STATE 5 zugewiesen ist, ist das Programm falsch, da kein übereinstimmender Status vorliegt. Der Compiler wird STATE = 5 jedoch nicht warnen

Es ist also besser, so zu verwenden

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

SampleState state = SampleStateGood;
Marcus Thornton
quelle