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

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

Например:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Что на самом деле здесь заявлено?

вопрос задан 1.04.2009
Craig
7861 репутация

14 ответов


  • 1535 рейтинг

    Здесь объявляются три вещи: анонимный перечислимый тип объявляется, 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 анонимным и объявить его только с именем typedef:

    typedef enum { ... } tagname;
    

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

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

    ответ дан Adam Rosenfield, с репутацией 297597, 1.04.2009
  • 242 рейтинг

    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 здесь .

    ОБНОВЛЕНИЕ: ссылка на официальную документацию здесь .

    ответ дан Vladimir Grigorov, с репутацией 6883, 6.03.2013
  • 47 рейтинг

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

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

    Выше приведено только перечисление тегов shapeType.

    ответ дан hburde, с репутацией 1318, 15.03.2012
  • 34 рейтинг

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

    ответ дан Brian Mitchell, с репутацией 2115, 1.04.2009
  • 28 рейтинг

    Обновление для 64-разрядных изменений: Согласно Apple Docs о 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
        }
    
    ответ дан Mani, с репутацией 13927, 29.01.2014
  • 25 рейтинг

    Enum - это определенный пользователем тип данных. Перечисленные типы данных Переменные типа данных могут принимать только те значения, которые были ранее объявлены.

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

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

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

    ответ дан annu, с репутацией 354, 17.10.2012
  • 23 рейтинг

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

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

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

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

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

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

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

    Тогда, если вы хотите повторно использовать тот же набор перечислителей (здесь хз. , , 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;
    

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

    Это последний шаг нашего великого продвижения к вершине. Просто добавив 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
    

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

    Хороший Enum!

    ответ дан Vincent Zgueb, с репутацией 1421, 10.03.2013
  • 10 рейтинг

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

    typedef unsigned long int TWOWORDS;
    

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

    TWOWORDS var1, var2;
    

    вместо

    unsigned long int var1, var2;
    
    ответ дан Rajneesh071, с репутацией 23004, 18.06.2013
  • 7 рейтинг
    typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
    } ShapeType;
    

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

     ShapeType shape;
    

    и

     enum {
        kCircle,
        kRectangle,
        kOblateSpheroid
    } 
    ShapeType;
    

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

    enum ShapeType shape;
    
    ответ дан Vivek Sehrawat, с репутацией 5552, 25.12.2013
  • 4 рейтинг

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

    ответ дан Priyanka Naik, с репутацией 125, 16.03.2014
  • 2 рейтинг

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

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

    ответ дан does_not_exist, с репутацией , 27.12.2014
  • 2 рейтинг

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

    typedef enum {
        kCircle,
        kRectangle,
        kOblateSpheroid
    } ShapeType;
    

    Здесь он создает перечислимый тип данных ShapeType & amp; мы можем написать новые имена для типа enum ShapeType , как указано ниже

    ShapeType shape1; 
    ShapeType shape2; 
    ShapeType shape3;
    
    ответ дан Yogeesh H T, с репутацией 1519, 16.11.2015
  • 2 рейтинг

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

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

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

    typedef enum : NSUInteger {
        kCircle, // for your value; kCircle = 5, ...
        kRectangle,
        kOblateSpheroid
    } ShapeType;
    
    ShapeType circleShape = kCircle;
    NSLog(@"%lu", (unsigned long) circleShape); // prints: 0
    
    ответ дан Bilal Arslan, с репутацией 87, 30.03.2016
  • 0 рейтинг
    Enum

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

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

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

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

    typedef enum SampleState {
        SampleStateGood  = 0,
        SampleStateBad,
        SampleStateOther
    } SampleState;
    
    SampleState state = SampleStateGood;
    
    ответ дан Marcus Thornton, с репутацией 2933, 21.06.2018