Objective-C Перечисление, NS_ENUM & NS_OPTIONS

Каков правильный способ создания перечисления с определенным типом в Objective-C? Как работают NS_ENUM и NS_OPTIONS? NS_OPTIONS используются для маски, например NSAutoresizing? Спасибо.

Code from NSObjCRuntime.h
    #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
    #define NS_OPTIONS(_type, _name) _type _name; enum : _type

Ответы

Ответ 1

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

вместо

typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
} UITableViewCellStyle;

или

typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

typedef NSInteger UITableViewCellStyle;

сделайте следующее:

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

пример NS_OPTIONS перечисление:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

Ответ 2

Существует разница между двумя, за исключением того, что они вызывают различные виды перечислений.

При компиляции в режиме Objective-C ++ они генерируют другой код:

это исходный код:

typedef NS_OPTIONS(NSUInteger, MyOptionType) {
    MyOptionType1 = 1 << 0,
    MyOptionType2 = 1 << 1,
};

typedef NS_ENUM(NSUInteger, MyEnumType) {
    MyEnumType1 = 1 << 0,
    MyEnumType2 = 1 << 1,
};

это код, когда макросы расширяются в Objective-C компиляции:

typedef enum MyOptionType : NSUInteger MyOptionType; enum MyOptionType : NSUInteger {
    MyOptionType1 = 1 << 0,
    MyOptionType2 = 1 << 1,
};

typedef enum MyEnumType : NSUInteger MyEnumType; enum MyEnumType : NSUInteger {
    MyEnumType1 = 1 << 0,
    MyEnumType2 = 1 << 1,
};

это код, когда макросы расширяются в Objective-C++ компиляции:

typedef NSUInteger MyOptionType; enum : NSUInteger {
    MyOptionType1 = 1 << 0,
    MyOptionType2 = 1 << 1,
};

typedef enum MyEnumType : NSUInteger MyEnumType; enum MyEnumType : NSUInteger {
    MyEnumType1 = 1 << 0,
    MyEnumType2 = 1 << 1,
};

См. разницу NS_OPTIONS между двумя режимами?

HERE IS THE REASON:

В С++ 11 есть новая функция, вы можете объявить тип для перечисления, до этого перечисление типа hold определяется компилятором в соответствии с наибольшим значением перечислений.

Итак, в С++ 11, поскольку вы можете самостоятельно определить размер своего перечисления, вы можете перенаправить объявить перечисления, не определяя их, например:

//forward declare MyEnumType
enum MyEnumType: NSInteger

//use myEnumType
enum MyEnumType aVar;

//actually define MyEnumType somewhere else
enum MyEnumType: NSInteger {
    MyEnumType1 = 1 << 1,
    MyEnumType2 = 1 << 2,
}

Эта функция удобна, а Objective-C импортирует эту функцию, но при выполнении побитового вычисления возникает проблема:

enum MyEnumType aVar = MyEnumType1 | MyEnumType2;

Этот код не может компилироваться в компиляции С++/ Objective-C ++, так как aVar рассматривается как тип NSInteger, но MyEnumType1 | MyEnumType2 имеет тип MyEnumType, это назначение не может выполняться без литья типов, С++ запрещает неявное литье типов.

В настоящее время нам нужны NS_OPTIONS, NS_OPTIONS возвращаются к перечислению перед С++ 11, так что нет MyEnumType действительно, MyEnumType - это просто другое имя для NSInteger, поэтому код типа

enum MyEnumType aVar = MyEnumType1 | MyEnumType2; 

будет компилироваться, поскольку он присваивает NSInteger NSInteger.