22

在 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
4

2 回答 2

35

来自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
};
于 2012-12-29T12:08:02.803 回答
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,
};

这是在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

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,
}

这个特性很方便,Objective-C 引入了这个特性,但是在做按位计算的时候带来了一个问题,像这样:

enum MyEnumType aVar = MyEnumType1 | MyEnumType2;

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

这时候,我们需要NS_OPTIONS,NS_OPTIONS回退到C++ 11之前的enum,这样MyEnumType确实没有,MyEnumType只是另外一个名字NSInteger,这样代码就好了

enum MyEnumType aVar = MyEnumType1 | MyEnumType2; 

将编译,因为它分配NSIntegerNSInteger.

于 2014-12-08T02:03:06.770 回答