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
.