美文网首页iOS杂问题iOS知识总结
详解枚举NS_OPTIONS与NS_ENUM的区别与格式

详解枚举NS_OPTIONS与NS_ENUM的区别与格式

作者: CombatReadiness | 来源:发表于2016-05-17 10:51 被阅读9556次

    NS_OPTIONS

    typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) {
        UISwipeGestureRecognizerDirectionNone = 0,  //值为0
        UISwipeGestureRecognizerDirectionRight = 1 << 0,  //值为2的0次方
        UISwipeGestureRecognizerDirectionLeft = 1 << 1,  //值为2的1次方
        UISwipeGestureRecognizerDirectionUp = 1 << 2,  //值为2的2次方
        UISwipeGestureRecognizerDirectionDown = 1 << 3  //值为2的3次方
    };
    

    小括号中第一个为NSUInteger这个为固定值,第二个为枚举类型,自己定义,大括号中枚举项必须全部包含小括号的枚举类型,枚举项后面再跟上几个值的区别,这里枚举项是NSUInteger类型,它的值我已经标记了,看上面注释,当然也可以像下方这样写枚举,但是官方推荐格式为上面那种。

    typedef enum {
        UISwipeGestureRecognizerDirectionNone = 0,  //值为0
        UISwipeGestureRecognizerDirectionRight = 1 << 0,  //值为2的0次方
        UISwipeGestureRecognizerDirectionLeft = 1 << 1,  //值为2的1次方
        UISwipeGestureRecognizerDirectionUp = 1 << 2,  //值为2的2次方
        UISwipeGestureRecognizerDirectionDown = 1 << 3  //值为2的3次方
    }UISwipeGestureRecognizerDirection;
    

    NS_ENUM

    typedef NS_ENUM(NSInteger, NSWritingDirection) {
        NSWritingDirectionNatural = -1,  //值为-1    
        NSWritingDirectionLeftToRight = 0,  //值为0
        NSWritingDirectionRightToLeft = 1  //值为1       
    };
    

    小括号中第一个为NSInteger这个为固定值,第二个为枚举类型,自己定义,大括号中枚举项必须包含小括号中自己定义的枚举类型,枚举项自己加后缀以视区别,大括号中的枚举项的值可自定义,若是定义了枚举项其中一项的值后面依次在它的前一项的值上加1,如这样:

    typedef NS_ENUM(NSInteger, NSWritingDirection) {
        NSWritingDirectionNatural = 0,  //值为0    
        NSWritingDirectionLeftToRight,  //值为1
        NSWritingDirectionRightToLeft  //值为2       
    };
    //或者这样
    typedef NS_ENUM(NSInteger, NSWritingDirection) {
        NSWritingDirectionNatural = 0,  //值为0    
        NSWritingDirectionLeftToRight = 2,  //值为2
        NSWritingDirectionRightToLeft  //值为3       
    };
    //若是都不定义值,默认第一项为0,后面依次枚举项的值加1。
    

    当然也可以下方这样写枚举,但是官方不推荐,还是上面格式规范

    typedef enum {
        NSWritingDirectionNatural = -1,  //值为-1    
        NSWritingDirectionLeftToRight = 0,  //值为0
        NSWritingDirectionRightToLeft = 1  //值为1  
    }NSWritingDirection;
    

    NS_ENUM与NS_OPTIONS区别

    • NS_ENUM枚举项的值为NSInteger,NS_OPTIONS枚举项的值为NSUInteger;

      这里为什么NS_ENUM用NSInteger,NS_OPTIONS用NSUInteger看后面总结。

    • NS_ENUM定义通用枚举,NS_OPTIONS定义位移枚举

      位移枚举即是在你需要的地方可以同时存在多个枚举值如这样:

      UISwipeGestureRecognizer *swipeGR = [[UISwipeGestureRecognizer alloc] init];
      swipeGR.direction = UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionLeft | UISwipeGestureRecognizerDirectionRight;
      //这里几个枚举项同时存在表示它的方向同时包含1.向下2.向左3.向右
    
    而NS_ENUM定义的枚举不能几个枚举项同时存在,只能选择其中一项,像这样:
    
    NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
    paragraph.baseWritingDirection = NSWritingDirectionNatural;
    
    • NS_OPTIONS的枚举项的值需要像这样表示1 << 0,1 << 1,2的几次方这样,而NS_ENUM可以直接给像1,2,3这样。

    总结:

    这里为什么会出现NS_OPTIONS与NS_ENUM且为什么不直接一个就行,且枚举值可多选。因为有个是否将代码按照C++模式编译,若是不按照C++模式编译,NS_OPTIONS与NS_ENUM展开方式就一样,若是要按照C++模式编译,就不同了。在使用或运算操作两个枚举值时,C++默认为运算结果的数据类型是枚举的底层数据类型即NSUInteger,且C++不允许它隐式转换为枚举类型本身,所以C++模式下定义了NS_OPTIONS宏以保证不出现类型转换。
    到了这我们就知道了只要枚举值需要用到按位或(2个及以上枚举值可多个存在)就使用NS_OPTIONS,否则使用NS_ENUM。

    相关文章

      网友评论

      • 走停2015_iOS开发:你好 这个是不是有问题 我一直理解是
        UISwipeGestureRecognizerDirectionNone = 0, //值为0
        UISwipeGestureRecognizerDirectionRight = 1 << 0, //值为1
        UISwipeGestureRecognizerDirectionLeft = 1 << 1, //值为10的十进制
        UISwipeGestureRecognizerDirectionUp = 1 << 2, //值为100的十进制
        UISwipeGestureRecognizerDirectionDown = 1 << 3 //值为100的十进制
        696016f77fc2:那你怎么理解做异或这类的运算的。。。。偏差有点大啊
        Super_Yuan:TestTypeSample = Sample << N;结果就是将Sample的二进制数向左移动N位,即Sample乘以2的N次方
      • Bwing:针对 “这里为什么NS_ENUM用NSInteger,NS_OPTIONS用NSUInteger看后面总结。” 这个问题,个人觉得总结里面的答案是不对的,C++ 默认为运算结果的数据类型是枚举的底层数据类型,但不一定是 NSUInteger,总结里的话应该是解释了为什么要有 NS_ENUM 和 NS_OPTION。可以参见一下宏定义:
        #if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))
        #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
        #if (__cplusplus)
        #define NS_OPTIONS(_type, _name) _type _name; enum : _type
        #else
        #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type
        #endif
        #else
        #define NS_ENUM(_type, _name) _type _name; enum
        #define NS_OPTIONS(_type, _name) _type _name; enum
        #endif
        CodingEleven:NS_ENUM 使用NSUInteger也是没问题的
      • Wang66:之所以对枚举要进行位移赋值,是为了保证多个枚举值组合后结果的唯一性。NS_OPTIONS是自动帮我们进行了位移赋值,而我们也可以对NS_ENUM手动进行位移赋值,也能达到多个值组合后结果唯一的效果。
      • 不懂冯先生:不错, 不错
      • FindCrt:写的不错。关于为什么用位运算来实现多个枚举值的“或”,我有写过一点思考http://www.jianshu.com/p/4f896df73d11,有兴趣的可以看看
      • dslCoding:你好这个NS_OPTIONS中为什么要用位移操作,这样做有什么好处吗,请求帮助

        CombatReadiness:老哥,稳:wink:
        甘邦:应该是说按位或操作,需要用NS_OPTIONS这个宏来定义。这里主要是防止代码按C++模式编译,与NS_ENUM有所不同,C++不允许“隐式转换”。如果是这个枚举值只需要使用一个的话,就可以用NS_ENUM定义;像UI那种使用多个枚举值的,就使用NS_OPTIONS:grin:
        CombatReadiness:像你app中有远程推送时,是不是可定义badge,alert,sound几种嘛,NS_OPTIONS就是为了让你可多选,NS_ENUM你可以看做是switch case,只能选择其中一种。
      • iOS入门级攻城尸:言简意赅,好文章!
      • CombatReadiness:@kakarotto
        我不是掌柜:或者用NSUInteger做NS_ENUM的类型
        我不是掌柜:那我能用NSInteger做NS_OPTIONS的类型么
      • 我不是掌柜:NS_ENUM枚举项的值为NSInteger,NS_OPTIONS枚举项的值为NSUInteger;
        这个对么

      本文标题:详解枚举NS_OPTIONS与NS_ENUM的区别与格式

      本文链接:https://www.haomeiwen.com/subject/kzqirttx.html