简体   繁体   English

NS_ENUM和NS_OPTIONS有什么区别?

[英]What is the difference between NS_ENUM and NS_OPTIONS?

I preprocessed following code with clang in Xcode5. 我在Xcode5中使用clang预处理了以下代码。

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

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

And got this. 得到了这个。

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

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

I know NS_OPTIONS is for a bitmask, but is there any technical differences? 我知道NS_OPTIONS用于位掩码,但是有任何技术差异吗? Or this is just for naming convention? 或者这仅仅是为了命名约定?

EDIT 编辑

According to the definition of NS_OPTIONS, it's probably for compiler compatibility.(especially for c++ compiler) 根据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

__cplusplus value in clang is 199711 and I can't test what this is exactly for, though. clang中的__cplusplus值是199711,但我无法测试这究竟是什么。

There's a basic difference between an enum and a bitmask (option). 枚举和位掩码(选项)之间存在基本区别。 You use an enum to list exclusive states. 您使用枚举列出独占状态。 A bitmask is used when several properties can apply at the same time. 当多个属性可以同时应用时,使用位掩码。

In both cases you use integers, but you look at them differently. 在这两种情况下,您都使用整数,但您会以不同的方式查看它们。 With an enum you look at the numerical value, with bitmasks you look at the individual bits. 使用枚举,您可以查看数值,使用位掩码查看各个位。

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

Will only represent two states. 只会代表两个州。 You can simply check it by testing for equality. 您可以通过测试相等性来检查它。

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

While the bitmask will represent more states. 而位掩码将代表更多的状态。 You check for the individual bits with logic or bitwise operators. 您可以使用逻辑或按位运算符检查各个位。

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 An enum gives names to numbers. tl; dr枚举为数字命名。 A bitmask gives names to bits. 位掩码为位提供名称。

The only major difference is that using the appropriate macro allows Code Sense (Xcode's code completion) to do type checking and code completion better. 唯一的主要区别是使用适当的宏允许Code Sense(Xcode的代码完成)更好地进行类型检查和代码完成。 For example, NS_OPTIONS allows the compiler to make sure all the enums you | 例如,NS_OPTIONS允许编译器,以确保所有的枚举你| together are of the same type. 一起属于同一类型。

For further reading see: http://nshipster.com/ns_enum-ns_options/ 如需进一步阅读,请访问: http//nshipster.com/ns_enum-ns_options/

Edit: 编辑:

Now that Swift is coming, using NS_ENUM/OPTIONS is highly recommended so that the enum can be correctly bridged to a swift enum. 现在Swift即将推出,强烈建议使用NS_ENUM / OPTIONS,以便枚举可以正确地桥接到快速枚举。

The only difference is to let developers using the values know if it makes sense to use them in an OR 'ed bitmask. 唯一的区别就是让使用值的开发人员知道,如果它是有道理的在使用它们OR “版位掩码。

The compiler doesn't care which one you use though :) 编译器不关心你使用哪一个:)

I copied my answer from this question Objective-C Enumeration, NS_ENUM & NS_OPTIONS : 我从这个问题中复制了我的答案Objective-C Enumeration,NS_ENUM和NS_OPTIONS

Since the user who add that question hasn't been active for a long time, maybe you can suggest my answers for people who search and find here. 由于添加该问题的用户长时间没有活动,也许您可​​以为搜索和查找此处的人建议我的答案。

BELOW IS THE ANSWER COPIED : 以下是答复

There is a difference between the two except that they infer different kind of enumerations. 除了他们推断出不同类型的枚举之外,两者之间存在差异。

When compiled in Objective-C++ mode, they generate different code: 在Objective-C ++模式下编译时,它们会生成不同的代码:

this is the original code: 这是原始代码:

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

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

this is the code when macros are expanded in Objective-C compiling: 这是在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,
};

this is the code when macros are expanded in Objective-C++ compiling: 这是在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,
};

See the difference of NS_OPTIONS between two modes? 看两种模式之间的NS_OPTIONS的区别?

HERE IS THE REASON : HERE IS THE REASON

There is a new feature in C++ 11, you can declare a type for you enumeration, before that, the type holding enumeration is decided by compiler according to the largest value of enumerations. C ++ 11中有一个新功能,您可以为枚举声明一个类型,在此之前,类型持有枚举由编译器根据枚举的最大值决定。

So in C++ 11, since you can decide the size of your enumeration by yourself, you could forward declare enums without actually define them, like this: 所以在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,
}

This feature is handy, and Objective-C imports this feature , but it brings a problem, when doing bitwise calculation, like this: 这个功能很方便,Objective-C导入了这个功能,但是在进行按位计算时会带来一个问题,如下所示:

enum MyEnumType aVar = MyEnumType1 | MyEnumType2;

This code can't compile in C++/Objective-C++ compiling, since aVar is considered of type NSInteger but MyEnumType1 | MyEnumType2 此代码无法在C ++ / Objective-C ++编译中编译,因为aVar被认为是NSInteger类型但MyEnumType1 | MyEnumType2 MyEnumType1 | MyEnumType2 is of type MyEnumType , this assignment can't perform without a type cast, C++ forbids implicit type casting . MyEnumType1 | MyEnumType2的类型为MyEnumType ,如果没有类型MyEnumType ,则此赋值无法执行, C ++禁止隐式类型转换

At this time, we need NS_OPTIONS, NS_OPTIONS fall back to enum before C++ 11, so that there is no MyEnumType indeed, MyEnumType is just another name for NSInteger , so that code like 这时,我们需要NS_OPTIONS,NS_OPTIONS回退到C ++ 11之前的枚举,所以确实没有MyEnumTypeMyEnumType只是NSInteger另一个名称,所以代码就像

enum MyEnumType aVar = MyEnumType1 | MyEnumType2; 

will compile, since it is assigning NSInteger to NSInteger . 将编译,因为它将NSInteger分配给NSInteger

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM