Co to jest wyliczenie typedef w Objective-C?


1087

Nie sądzę, że zasadniczo rozumiem, co to enumjest i kiedy go używać.

Na przykład:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Co tak naprawdę deklaruje się tutaj?


2
Czy typ zdefiniowany przez użytkownika nazywa się „enum”? Tak myślałem, dopóki nie natknąłem się na kod, który zawierał wiele deklaracji typu „enum”.
Craig,

8
Nie, typ zdefiniowany przez użytkownika to ShapeType. Czytaj dalej na typedef: en.wikipedia.org/wiki/Typedef
rampion

6
Typedef w Objective-C jest dokładnie taki sam, jak typedef w C. A enum w Objective-C jest dokładnie taki sam jak enum w C. To deklaruje enum z trzema stałymi kCircle = 0, kRectangle = 1 i kOblateSpheroid = 2 i nadaje typowi wyliczenia nazwę ShapeType. Jeśli nie wiesz, co oznaczają słowa „typedef” i „enum”, kup książkę o C.
gnasher729

Odpowiedzi:


1565

Trzy rzeczy są deklarowane są tutaj: anonimowy typ wyliczeniowy jest deklarowana, ShapeTypejest ogłoszony typedef dla tego anonimowe wyliczanie, a trzy nazwy kCircle, kRectanglei kOblateSpheroidzostały zadeklarowane jako integralne stałych.

Rozwalmy to. W najprostszym przypadku wyliczenie można zadeklarować jako

enum tagname { ... };

To deklaruje wyliczenie ze znacznikiem tagname. W C i Objective-C (ale nie w C ++) wszelkie odniesienia do tego muszą być poprzedzone enumsłowem kluczowym. Na przykład:

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

Aby uniknąć konieczności używania enumsłowa kluczowego w dowolnym miejscu, można utworzyć typedef:

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

Można to uprościć w jednym wierszu:

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

I wreszcie, jeśli nie potrzebujemy, aby móc korzystać enum tagnamez enumhasła, możemy dokonać enumanonimowy i tylko zadeklarować ją z nazwą typedef:

typedef enum { ... } tagname;

Teraz w tym przypadku deklarujemy, że jesteśmy ShapeTypeanonimowym wyliczeniem na maszynie. ShapeTypejest naprawdę tylko integralną typu i powinny być wykorzystywane jedynie zadeklarować zmienne, które posiadają jedną z wartości wymienionych w deklaracji (czyli jeden kCircle, kRectanglei kOblateSpheroid). Możesz jednak przypisać ShapeTypezmienną inną wartość poprzez rzutowanie, więc musisz zachować ostrożność podczas odczytywania wartości wyliczeniowych.

Wreszcie kCircle, kRectanglei kOblateSpheroidzostały zadeklarowane jako integralne stałe w globalnej przestrzeni nazw. Ponieważ nie określono żadnych konkretnych wartości, są one przypisywane do kolejnych liczb całkowitych rozpoczynających się od 0, więc kCirclewynosi 0, kRectanglewynosi 1 i kOblateSpheroidwynosi 2.


6
Ładne wyjaśnienie - aby dodać jedną rzecz, struct przestrzega podobnych zasad nazewnictwa w C (nie jestem pewien co do Celu-C).
Michael Burr

109
Cel C jest właściwym nadzbiorem C. Wszystkie reguły nazewnictwa struktury C w C są tak samo ważne w Celu C.
sigjuice

Niesamowite. Czy mogę po prostu użyć enum w stylu C ++, a także nie muszę pisać enum :)
user4951

11
Można użyć wyliczeń w stylu C ++, jeśli plik, w którym je zadeklarujesz, jest plikiem .mm, a nie .m. Objective-C ++ jest absurdalnie potężny.
Kevin Hoffman

14
A kiedy już zastanowisz się nad tą odpowiedzią, warto spojrzeć na nowe NS_ENUM i NS_OPTIONS. Samouczek tutaj: nshipster.com/ns_enum-ns_options i SO tutaj: stackoverflow.com/questions/14080750/…
Snowcrash

254

Apple zaleca zdefiniowanie takich wyliczeń od Xcode 4.4 :

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

Zapewniają również przydatne makro NS_ENUM:

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

Te definicje zapewniają silniejsze sprawdzanie typów i lepsze uzupełnianie kodu. Nie mogłem znaleźć oficjalnej dokumentacji NS_ENUM, ale możesz obejrzeć film „Modern Objective-C” z sesji WWDC 2012 tutaj .


AKTUALIZACJA
Link do oficjalnej dokumentacji tutaj .


13
Część o „Enum Improvements” zaczyna się o 5:58
vikingosegundo

5
Jak skomentowano inną odpowiedź, zobacz wyjaśnienie NS_ENUMmakra Apple'a przez NSHipster: NSHipster.com/ns_enum-ns_options
Basil Bourque,

1
To jest link do oficjalnej dokumentacji o NS_ENUM: developer.apple.com/library/ios/releasenotes/ObjectiveC/…
YoGiN

50

Wyliczenie deklaruje zestaw uporządkowanych wartości - typedef po prostu dodaje do tego poręczną nazwę. Pierwszy element to 0 itd.

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

WORKDAYS today = Monday;

Powyższe jest tylko wyliczeniem znaczników shapeType.


34

Użytkownik definiuje typ, który ma możliwych wartości kCircle, kRectanglelub kOblateSpheroid. Jednak wartości w wyliczeniu (kCircle itp.) Są widoczne poza wyliczeniem. Ważne jest, aby o tym pamiętać ( int i = kCircle;na przykład obowiązuje).


30

Aktualizacja dotycząca zmiany 64-bitowej: Według dokumentów Apple na temat zmian 64-bitowych,

Wyliczane są również typy: W kompilatorze LLVM typy wyliczone mogą określać rozmiar wyliczenia. Oznacza to, że niektóre wyliczone typy mogą mieć również rozmiar większy niż się spodziewasz. Rozwiązaniem, podobnie jak we wszystkich innych przypadkach, jest brak jakichkolwiek założeń dotyczących wielkości typu danych. Zamiast tego przypisz dowolne wyliczone wartości do zmiennej o odpowiednim typie danych

Więc musisz utworzyć wyliczenie z typem jak poniżej składni, jeśli obsługujesz 64-bit.

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

lub

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

W przeciwnym razie doprowadzi to do ostrzeżenia jako Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

Aktualizacja do szybkiego programowania:

W krótkim czasie następuje zmiana składni.

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }

Jeśli konieczne jest przekazanie dalej, zadeklaruj wyliczenie (NS_ENUM): stackoverflow.com/a/42009056/342794
lal

25

Wyliczenie (skrót wyliczenia) służy do wyliczenia zestawu wartości (podmiotów wyliczających). Wartość jest abstrakcyjną rzeczą reprezentowaną przez symbol (słowo). Na przykład podstawowym wyliczeniem może być

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

Ten wylicznik nazywa się anonimowy, ponieważ nie masz symbolu, który mógłby go nazwać. Ale nadal jest całkowicie poprawne. Po prostu użyj tego w ten sposób

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

Ok. Życie jest piękne i wszystko idzie dobrze. Ale pewnego dnia musisz ponownie użyć tego wyliczenia, aby zdefiniować nową zmienną do przechowywania myGrandFatherPantSize, a następnie piszesz:

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

Ale wtedy pojawia się błąd kompilatora „redefinicja modułu wyliczającego”. W rzeczywistości problem polega na tym, że kompilator nie jest pewien, że najpierw wyliczysz, a ty drugi to samo.

Następnie, jeśli chcesz ponownie użyć tego samego zestawu modułów wyliczających (tutaj xs ... xxxxl) w kilku miejscach, musisz oznaczyć go unikalną nazwą. Przy drugim użyciu tego zestawu wystarczy użyć tagu. Ale nie zapominaj, że ten znacznik nie zastępuje słowa wyliczeniowego, a jedynie zestaw jednostek wyliczających. Następnie, jak zwykle, używaj enum. Lubię to:

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

możesz go również użyć w definicji parametru:

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

Można powiedzieć, że przepisywanie enum wszędzie nie jest wygodne i sprawia, że ​​kod wygląda trochę dziwnie. Masz rację. Prawdziwy typ byłby lepszy.

To ostatni krok naszego wielkiego postępu na szczyt. Po prostu dodając typedef przekształćmy nasze wyliczenie w prawdziwy typ. Aha, ostatnia rzecz, typedef nie jest dozwolony w twojej klasie. Następnie określ swój typ tuż powyżej. Zrób to tak:

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

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

Pamiętaj, że tag jest opcjonalny. Następnie, ponieważ tutaj, w tym przypadku, nie tagujemy modułów wyliczających, a jedynie definiujemy nowy typ. Więc tak naprawdę nie potrzebujemy już tego.

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

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

Jeśli rozwijasz się w Objective-C z XCode, pozwolę ci odkryć kilka fajnych makr z prefiksem NS_ENUM. Powinno to pomóc w łatwym zdefiniowaniu dobrych wyliczeń, a ponadto pomoże statycznemu analizatorowi wykonać kilka interesujących kontroli przed kompilacją.

Dobry Enum!


Zawsze myślałem „dlaczego ktokolwiek miałby odpowiedzieć na pytanie, na które już udzielono odpowiedzi i które zaakceptowano”. Chłopie, cały czas się myliłem! To najlepsza odpowiedź i pomaga początkującym jak ja!
rak appdev 13.03.17

10

typedefjest przydatny do przedefiniowania nazwy istniejącego typu zmiennej. Zapewnia krótki i znaczący sposób na wywołanie typu danych. na przykład:

typedef unsigned long int TWOWORDS;

tutaj typ bez znaku long int jest redefiniowany na typ TWOWORDS. Dlatego możemy teraz deklarować zmienne typu unsigned long int, pisząc,

TWOWORDS var1, var2;

zamiast

unsigned long int var1, var2;

7
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

możesz użyć go w następujący sposób:

 ShapeType shape;

i

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

teraz możesz używać go w następujący sposób:

enum ShapeType shape;

3

enum służy do przypisywania wartości elementom wyliczającym, których nie można wykonać w strukturze. Dlatego za każdym razem zamiast uzyskiwać dostęp do pełnej zmiennej, możemy to zrobić według wartości, którą przypisujemy zmiennym w wyliczeniu. Domyślnie zaczyna się od przypisania 0, ale możemy przypisać mu dowolną wartość, a następnej zmiennej w enum zostanie przypisana wartość poprzedniej wartości +1.


3

Możesz użyć w poniższym formacie surowej wartości domyślnej od 0, więc

  • kCircle ma wartość 0,
  • k Prostokąt ma wartość 1,
  • kOblateSpheroid wynosi 2.

Możesz przypisać własną określoną wartość początkową.

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

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

2

Typedef pozwala programiście zdefiniować jeden typ Objective-C jako inny. Na przykład,

typedef int Counter; definiuje typ Licznik jako równoważny typowi int. To drastycznie poprawia czytelność kodu.


2

Typedef jest słowem kluczowym w językach C i C ++. Służy do tworzenia nowych nazw dla podstawowych typów danych (char, int, float, double, struct & enum) .

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Tutaj tworzy wyliczony typ danych ShapeType i możemy pisać nowe nazwy dla typu wyliczeniowego ShapeType, jak podano poniżej

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;

1

Wyliczanie może zmniejszyć wiele rodzajów „błędów” i sprawić, że kod będzie łatwiejszy do zarządzania

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

Definicja nie ma ograniczeń. To po prostu zmiana. Nie jest w stanie ograniczyć wszystkich warunków państwa. Kiedy STATE jest przypisane do 5, program będzie błędny, ponieważ nie ma pasującego stanu. Ale kompilator nie ostrzeże STATE = 5

Dlatego lepiej jest używać w ten sposób

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

SampleState state = SampleStateGood;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.