What is the difference between NS_ENUM and NS_OPTIONS?

前端 未结 4 1499
轻奢々
轻奢々 2021-01-30 04:47

I preprocessed following code with clang in Xcode5.

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

typedef NS_OPTIONS(NSInteger,         


        
4条回答
  •  不要未来只要你来
    2021-01-30 05:13

    I copied my answer from this question 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:

    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:

    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:

    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?

    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.

    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:

    //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:

    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 is of type MyEnumType, this assignment can't perform without a type cast, C++ forbids implicit type casting.

    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

    enum MyEnumType aVar = MyEnumType1 | MyEnumType2; 
    

    will compile, since it is assigning NSInteger to NSInteger.

提交回复
热议问题