What is the difference between NS_ENUM and NS_OPTIONS?

前端 未结 4 1402
轻奢々
轻奢々 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 04:47

    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. For example, NS_OPTIONS allows the compiler to make sure all the enums you | together are of the same type.

    For further reading see: 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.

    0 讨论(0)
  • 2021-01-30 04:53

    The only difference is to let developers using the values know if it makes sense to use them in an OR'ed bitmask.

    The compiler doesn't care which one you use though :)

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2021-01-30 05:14

    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. A bitmask gives names to bits.

    0 讨论(0)
提交回复
热议问题