Что такое перечисление typedef в Objective-C?

Я не думаю, что я принципиально понимаю, что такое enum и когда его использовать.

например:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

что на самом деле объявляется здесь?

14 ответов


здесь объявляются три вещи: объявляется анонимный перечисляемый тип,ShapeType объявляется typedef для этого анонимного перечисления, и три имени kCircle, kRectangle и kOblateSpheroid объявляются как интегральные константы.

давайте, что вниз. В простейшем случае перечисление может быть объявлено как
enum tagname { ... };

это объявляет перечисление с тегом tagname. В C и Objective-C (но не C++), любой ссылки на это должны будет начинаться с enum ключевое слово. Например:

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

чтобы избежать необходимости использовать enum ключевое слово везде, typedef может быть создан:

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

это можно упростить в одну строку:

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

и, наконец, если нам не нужно иметь возможность использовать enum tagname С enum ключевое слово, мы можем сделать enum anonymous и только объявить его с помощью typedef имя:

typedef enum { ... } tagname;

Итак, в этом случае, мы объявляем ShapeType чтобы быть typedef'Ed имя анонимного перечисления. ShapeType действительно просто интегральный тип и должен использоваться только для объявления переменных, которые содержат одно из значений, перечисленных в объявлении (то есть одно из kCircle, kRectangle и kOblateSpheroid). Вы можете назначить ShapeType переменной другое значение с помощью литья, поэтому вы должны быть осторожны при чтении значений enum.

наконец, kCircle, kRectangle, и kOblateSpheroid объявляются как интегральные константы в глобальном пространстве имен. Поскольку конкретные значения не указаны, они присваиваются последовательным целым числам, начинающимся с 0, поэтому kCircle 0, то kRectangle 1 и kOblateSpheroid is 2.


Apple рекомендует определять перечисления, подобные этому, начиная с Xcode 4.4:

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

Они также предоставляют удобный макрос NS_ENUM:

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

эти определения обеспечивают более сильную проверку типа и лучшее завершение кода. Я не смог найти официальную документацию NS_ENUM, но вы можете посмотреть видео "Modern Objective-C" с сессии WWDC 2012 здесь.

обновление: ссылка на официальную документацию здесь.


перечисление объявляет набор упорядоченных значений - typedef просто добавляет удобное имя к этому. 1-й элемент равен 0 и т. д.

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

WORKDAYS today = Monday;

выше - это просто перечисление тегов shapeType.


пользовательский тип, который имеет возможные значения kCircle, kRectangle или kOblateSpheroid. Однако значения внутри перечисления (kCircle и т. д.) видны вне перечисления. Важно иметь это в виду (int i = kCircle; - это справедливо, например).


обновление для 64-битного изменения: Согласно яблочный документов о 64-битных изменениях,

перечисления также типизированы : в компиляторе LLVM перечисляемые типы могут определите размер перечисления. Это означает, что некоторые перечисленные типы также могут иметь размер больше, чем вы ожидаете. Этот решение, как и во всех других случаях, состоит в том, чтобы не делать предположений о размер типа данных. Вместо этого назначьте переменной все перечисленные значения с правильным типом данных

так надо создать перечисление с типом как показано ниже синтаксиса, если вы поддерживаете 64-бит.

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

или

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

в противном случае, это приведет к предупреждения как Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

обновление для swift-программирования:

в swift происходит изменение синтаксиса.

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

Enum-определяемый пользователем тип данных. ПЕРЕЧИСЛЯЕМЫЕ ТИПЫ ДАННЫХ Перечисленные переменные типа данных могут принимать только те значения, которые были объявлены ранее.

enum month { jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
enum month this_month;

this_month = feb;

в приведенном выше объявлении месяц объявляется как перечисленный тип данных. Он состоит из набора значений с января по декабрь. Численно Янь получает значение 1, февраль-значение 2 и так далее.

переменная this_month объявляется того же типа, что и month, затем присваивается значение, связанное с февраль. This_month не может быть присвоено никаких значений за пределами указанных в списке инициализации для объявления месяца.


перечисление (аббревиатура перечисления) используется для перечисления набора значений (счетчиками). Значение-это любая абстрактная вещь, представленная символом (словом). Например, базовым перечислением может быть

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

это перечисление называется анонимным, потому что у вас нет символа, чтобы назвать его. Но это все равно совершенно правильно. Просто используйте его так

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

Ok. Жизнь прекрасна и все идет хорошо. Но однажды вам нужно повторно использовать это перечисление, чтобы определить новое переменная для хранения myGrandFatherPantSize, затем вы пишете:

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

но тогда у вас есть ошибка компилятора "переопределение перечислителя". На самом деле проблема в том, что компилятор не уверен, что первое перечисление и второе описывают одно и то же.

затем, если вы хотите повторно использовать тот же набор перечислителей (здесь xs...xxxxl) в нескольких местах вы должны пометить его уникальным именем. Во второй раз, когда вы используете этот набор, вам просто нужно использовать тег. Но не забывайте, что это тег не заменяет слово перечисления, а только набор перечислителей. Затем позаботьтесь об использовании enum как обычно. Вот так:

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

вы также можете использовать его в определении параметра:

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

вы можете сказать, что переписывание перечисления везде не удобно и делает код выглядит немного странно. Вы правы. Настоящий тип был бы лучше.

это последний шаг нашего великого продвижения к вершине. Просто добавив typedef, давайте преобразуем наше перечисление в реальном типе. О, последнее, typedef не допускается в вашем классе. Затем определите свой тип чуть выше. Сделайте это так:

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

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

помните, что тег является необязательным. Тогда, поскольку здесь в этом случае мы не помечаем перечислители, а просто определяем новый тип. Тогда нам больше не нужна.

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

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

если вы разрабатываете ObjectiveC с XCode, я позволю вам обнаружить некоторые хорошие макросы с префиксом NS_ENUM. Это должно помочь вам определить хорошие перечисления легко и сверх того поможет статическому анализатору сделать некоторые интересные проверки для вас перед компиляцией.

Хороший Перечисление !


typedef полезно для переопределения имени существующего типа переменной. Он предоставляет короткий и значимый способ вызова типа данных. е.г:

typedef unsigned long int TWOWORDS;

здесь тип unsigned long int переопределяется как тип TWOWORDS. Таким образом, теперь мы можем объявить переменные типа unsigned long int, написав,

TWOWORDS var1, var2;

вместо

unsigned long int var1, var2;

typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

затем вы можете использовать его как :-

 ShapeType shape;

и

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;
вы можете использовать его как:-
enum ShapeType shape;

enum используется для присвоения значения элементам enum, которые не могут быть выполнены в struct. Поэтому каждый раз вместо доступа к полной переменной мы можем сделать это по значению, которое мы присваиваем переменным в enum. По умолчанию он начинается с присвоения 0, но мы можем присвоить ему любое значение, и следующей переменной в enum будет присвоено значение Предыдущее значение +1.


a typedef позволяет программисту определять один тип Objective-C как другой. Например,

typedef Int Counter; определяет счетчик типов, эквивалентный типу int. Это значительно улучшает читаемость кода.


Typedef является ключевым словом в C и c++. Он используется для создания новых имен для основных типов данных (char, int, float, double, struct & enum).

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

здесь он создает перечисляемый тип данных ShapeType & мы можем написать новые имена для перечислимого типа ShapeType как показано ниже

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;

вы можете использовать в приведенном ниже формате, сырое значение по умолчанию, начиная с 0, поэтому

  • kCircle равно 0,
  • kRectangle - 1,
  • коблатесфероид равен 2.

вы можете назначить свое собственное начальное значение.

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

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

перечисление может уменьшить многие типы "ошибок" и сделать код более управляемым

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

определение не имеет ограничений. Это просто подмена. Она не в состоянии ограничить все условия государства. Когда состояние назначено 5, программа будет неправильной, потому что нет соответствующего состояния. Но компилятор не собирается предупреждать STATE = 5

Так что лучше использовать вот так

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

SampleState state = SampleStateGood;