32

我在 Xcode5 中使用 clang 预处理了以下代码。

typedef NS_ENUM(NSInteger, MyStyle) {
    MyStyleDefault,
    MyStyleCustom
};

typedef NS_OPTIONS(NSInteger, MyOption) {
    MyOption1 = 1 << 0,
    MyOption2 = 1 << 1,
};

并得到了这个。

typedef enum MyStyle : NSInteger MyStyle; enum MyStyle : NSInteger {
    MyStyleDefault,
    MyStyleCustom
};

typedef enum MyOption : NSInteger MyOption; enum MyOption : NSInteger {
    MyOption1 = 1 << 0,
    MyOption2 = 1 << 1,
};

我知道 NS_OPTIONS 用于位掩码,但有任何技术差异吗?或者这只是为了命名约定?

编辑

根据NS_OPTIONS的定义,可能是为了编译器的兼容性。(尤其是c++编译器)

// In CFAvailability.h
// Enums and Options
#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))
  #define CF_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
  #if (__cplusplus)
    #define CF_OPTIONS(_type, _name) _type _name; enum : _type
  #else
    #define CF_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
  #endif
#else
  #define CF_ENUM(_type, _name) _type _name; enum
  #define CF_OPTIONS(_type, _name) _type _name; enum
#endif

clang 中的 __cplusplus 值是 199711,但我无法测试这到底是为了什么。

4

4 回答 4

54

枚举和位掩码(选项)之间存在基本区别。您使用枚举来列出独占状态。当可以同时应用多个属性时,使用位掩码。

在这两种情况下,您都使用整数,但您对它们的看法不同。使用枚举查看数值,使用位掩码查看各个位。

typedef NS_ENUM(NSInteger, MyStyle) {
    MyStyleDefault,
    MyStyleCustom
};

只会代表两种状态。您可以通过测试是否相等来简单地检查它。

switch (style){
    case MyStyleDefault:
        // int is 0
    break;
    case MyStyleCustom:
        // int is 1
    break;
}

而位掩码将代表更多的状态。您可以使用逻辑或按位运算符检查各个位。

typedef NS_OPTIONS(NSInteger, MyOption) {
    MyOption1 = 1 << 0, // bits: 0001
    MyOption2 = 1 << 1, // bits: 0010
};

if (option & MyOption1){ // last bit is 1
    // bits are 0001 or 0011
}
if (option & MyOption2){ // second to last bit is 1
    // bits are 0010 or 0011
}
if ((option & MyOption1) && (option & MyOption2)){ // last two bits are 1
    // bits are 0011
}

tl; dr枚举为数字命名。位掩码为位命名。

于 2014-01-27T15:23:33.363 回答
17

唯一的主要区别是使用适当的宏可以让 Code Sense(Xcode 的代码完成)更好地进行类型检查和代码完成。例如, NS_OPTIONS 允许编译器确保您|在一起的所有枚举都属于同一类型。

如需进一步阅读,请参阅: http: //nshipster.com/ns_enum-ns_options/

编辑:

现在 Swift 即将到来,强烈建议使用 NS_ENUM/OPTIONS 以便枚举可以正确桥接到 swift 枚举。

于 2013-09-23T15:22:29.210 回答
7

OR唯一的区别是让使用这些值的开发人员知道在'ed 位掩码中使用它们是否有意义。

编译器并不关心你使用哪一个:)

于 2013-09-23T15:21:45.183 回答
1

我从这个问题Objective-C Enumeration, NS_ENUM & NS_OPTIONS复制了我的答案:

由于添加该问题的用户很长时间没有活跃,也许您可​​以为在这里搜索和查找的人建议我的答案。

以下是复制的答案

两者之间存在差异,只是它们推断出不同类型的枚举。

在 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:10:14.750 回答