Objective-C Enumeration,NS_ENUM和NS_OPTIONS

Llu*_*uís 20 cocoa enums objective-c

在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
Run Code Online (Sandbox Code Playgroud)

wat*_*n12 34

来自NSHipster的例子.NS_OPTIONS以类似的方式使用,但是对于通常是位掩码的枚举

代替

typedef enum {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
} UITableViewCellStyle;
Run Code Online (Sandbox Code Playgroud)

要么

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

typedef NSInteger UITableViewCellStyle;
Run Code Online (Sandbox Code Playgroud)

做这个:

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};
Run Code Online (Sandbox Code Playgroud)

一个例子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
};
Run Code Online (Sandbox Code Playgroud)


Car*_*loS 8

除了他们推断出不同类型的枚举之外,两者之间存在差异.

在Objective-C++模式下编译时,它们会生成不同的代码:

这是原始代码:

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

typedef NS_ENUM(NSUInteger, MyEnumType) {
    MyEnumType1 = 1 << 0,
    MyEnumType2 = 1 << 1,
};
Run Code Online (Sandbox Code Playgroud)

这是在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,
};
Run Code Online (Sandbox Code Playgroud)

这是在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,
};
Run Code Online (Sandbox Code Playgroud)

看两种模式之间的NS_OPTIONS的区别?

HERE IS THE REASON:

C++ 11中有一个新功能,您可以为枚举声明一个类型,在此之前,类型持有枚举由编译器根据枚举的最大值决定.

所以在C++ 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,
}
Run Code Online (Sandbox Code Playgroud)

这个功能很方便,Objective-C导入了这个功能,但是在进行按位计算时会带来一个问题,如下所示:

enum MyEnumType aVar = MyEnumType1 | MyEnumType2;
Run Code Online (Sandbox Code Playgroud)

此代码无法在C++/Objective-C++编译中编译,因为aVar被认为是类型NSIntegerMyEnumType1 | MyEnumType2属于类型MyEnumType,如果没有类型转换,此赋值不能执行,C++禁止隐式类型转换.

这时,我们需要NS_OPTIONS,NS_OPTIONS回退到C++ 11之前的枚举,所以MyEnumType确实没有,MyEnumType只是另一个名称NSInteger,所以代码就像

enum MyEnumType aVar = MyEnumType1 | MyEnumType2; 
Run Code Online (Sandbox Code Playgroud)

将编译,因为它被分配NSIntegerNSInteger.