谈谈位枚举NS_OPTIONS

给别人讲问题的时候遇到类似的,顺便就复习下。

谈谈位枚举NS_OPTIONS

在iOS开发中枚举大家用得最多的应该是NS_ENUM。NS_ENUM也没什么好讲的。主要来讲讲位枚举NS_OPTIONS。

下面是他们在Foundation.framework的NSObjCRuntime.h的定义

#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

其实从枚举定义来看,NS_ENUM和NS_OPTIONS本质是一样的,仅仅从字面上来区分其用途。NS_ENUM是通用情况,NS_OPTIONS一般用来定义具有位移操作或特点的情况(bitmask掩码)。

与、或操作

先讲讲关于二进制的位于操作。可能好多的同学都有些忘了。这里复习下。

位操作 解释 例子 应用
按位与(&) 有0则0,当俩位同时为1时返回1. 4=0000 0000 0000 0100 &7 =0000 0000 0000 0111= 0000 0000 0000 0100 1.清零
2.获取一个数据的指定位
3.保留数据区的特定位
按位或(` `) 有1则1,只要有一位为1则即可返回1. 5 = 0000 0000 0000 0101`

<<:左移运算符。左移k位 相当于 *2^k
>>:右移运算符。右移k位 相当于/2^k

实例

NS_OPTIONS位枚举的特点是可以使用位运算来处理枚举值,实际使用中可以用一个变量存储多个枚举值,表示互不影响的多个设置。比如系统中的UIViewAutoresizing定义如下。

enum UIViewAutoresizing {
    UIViewAutoresizingNone                 = 0, // 000000
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0, // 000001
    UIViewAutoresizingFlexibleWidth        = 1 << 1,// 000010
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,// 000100
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,// 001000
    UIViewAutoresizingFlexibleHeight       = 1 << 4,// 010000
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5,// 100000
}

为了说明问题这里就用UIViewAutoresizing举个例子。上面把对应的二进制写在了后面。现在要实现视图的宽和高自适应,UIViewAutoResizingFlexibleWidth| UIViewAutoresizingFlexibleHeight。

一般会这样写:

UIViewAutoresizing resizing = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

转换为二进制计算一下。

UIViewAutoresizing resizing = 000010 |010000 = 010010

这样就实现了变量保存多个枚举值。那么如何判断变量是否包含某个枚举值了,这的通过与操作。比如我要判断是否包含了UIViewAutoresizingFlexibleWidth

if (resizing & UIViewAutoresizingFlexibleWidth) {
       // UIViewAutoresizingFlexibleWidth is set
}

转换为二进制:

if (010010 & 000010) {
       // UIViewAutoresizingFlexibleWidth is set
}

010010 & 000010 = 000010 很明显不等于0。所以为YES。那么用一个不包含的试一下。

if (resizing & UIViewAutoresizingFlexibleTopMargin) {
       // UIViewAutoresizingFlexibleTopMargin is set
}

转为二进制

if (010010 & 001000) {
       // UIViewAutoresizingFlexibleTopMargin is set
}

很明显010010 & 001000 = 0,所以能够知道resizing不包含UIViewAutoresizingFlexibleTopMargin。

通过以上的这种方式实现了一个变量保存多个枚举值。也就是NS_OPTIONS的原理。

需要注意的地方

  1. 枚举命名方式尽量用系统的风格,比如枚举名为UIViewAutoresizing,具体的值为UIViewAutoresizingNone。简单来讲就是(枚举名+状态)
  2. 如果要实现一个变量保存多个枚举值就用NS_OPTIONS。个人觉得用NS_OPTIONS完全可以替代NS_ENUM。只需要在使用的时候不用与、或操作就可以了
  3. 用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
  4. 在处理枚举类型的switch语句中不要实现default分支。这样的话,加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举。
  5. 预留一个枚举值,用于扩展或者用于表示没有的情况

  转载请注明: Weslyxl 谈谈位枚举NS_OPTIONS

 上一篇
Dlib系列之在iOS中提取人脸特征点(第一篇) Dlib系列之在iOS中提取人脸特征点(第一篇)
最近因为工作需要,在研究人脸识别,图像处理这块,这里简单记录一下。今天主要讲讲前期的准备工作,比如由C++制作OC的静态库。 什么是dlib摘自官网: Dlib is a modern C++ toolkit containing m
下一篇 
解决mac下Spotlight和Notes(记事本)搜索失效 解决mac下Spotlight和Notes(记事本)搜索失效
由于换了mac,之前的习惯是把一些常用的文字资料放在Notes(记事本)中,这样可以在手机和电脑中实现资料互通。但是最近换了新mac,notes能够从Icloud中拿到同步的资料,但是始终搜索不出来。而且spotlight搜索也不起任何作用
2017-04-17
  目录