概述
在 C、C++、Java 这些语言中就有它们对应的枚举,定义的方式也多种多样,但使用目的只有一个:让代码可读性更强。这里我们只简单说说 Objective-C 中枚举的使用。
在 Apple 提供给我们的 API 中,经常会看到使用枚举的例子:
有这样的:
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
UIViewAnimationTransitionNone,
UIViewAnimationTransitionFlipFromLeft,
UIViewAnimationTransitionFlipFromRight,
UIViewAnimationTransitionCurlUp,
UIViewAnimationTransitionCurlDown,
};
还有这样的:
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
可以看到在 Objective-C 中为我们提供了两种定义宏的枚举:NS_ENUM 和 NS_OPTIONS,这两者其实本质上是一样的,都是用来声明枚举的,不过细小的区别还是有的:
NS_ENUM:常用来声明一般的 NSInteger 类型的枚举。
NS_OPTIONS:常用来声明 NSUinteger 类型的明位掩码(bitmasked)。
说明:用 enum 就可以声明一般类型和位掩码类型,但是苹果官方建议我们使用 NS_ENUM 和 NS_OPTIONS,它们可以推断出不同类型的枚举,还可以适配到不同的开发平台。
NS_OPTIONS
我们重点看看 NS_OPTIONS 类型的枚举:
在 NS_OPTIONS 类型的枚举中,我们看到每个枚举值后有 <<,其实这就是左移位运算符,这样我们就可以通过 |(或位运算符)进行组合使用,a << b 就表示把 a 转化为二进制后左移 b 位。
使用场景:如果一个枚举变量可能代表多个枚举值的时候,我们就需要声明成 NS_OPTIONS 类型的枚举。其原理只是把各个枚举值加起来(转化成十进制再想加),获得一个新值(十进制)。我们知道枚举值相对唯一,位运算就很好的解决了这个问题,它可以确保枚举值组合在一起的唯一性。
那么苹果官方是怎么知道我们多个条件组合使用了呢?答案是通过 &(与位运算符)进行判断的:
UIControlEvent controlEvents = UIControlEventEditingDidBegin | UIControlEventValueChanged | UIControlEventEditingDidEnd;
if (controlEvents & UIControlEventEditingDidBegin) {
NSLog(@"UIControlEventEditingDidBegin");
} else if (controlEvents & UIControlEventValueChanged) {
NSLog(@"UIControlEventValueChanged");
} else if (controlEvents & UIControlEventEditingDidEnd) {
NSLog(@"UIControlEventEditingDidEnd");
}
在这里我举例说明 NS_OPTIONS 类型枚举的用法:
typedef NS_OPTIONS(NSUInteger, MyType) {
MyTypeA = 1 << 0, // 值为1,2的0次方
MyTypeB = 1 << 1, // 值为2,2的1次方
MyTypeC = 1 << 2, // 值为4,2的2次方
MyTypeD = 1 << 3, // 值为8,2的3次方
};
// 使用
NSUInteger value = MyTypeA | MyTypeB;
NSLog(
@"%zd, %zd, %zd, %zd",
value & MyTypeA,
value & MyTypeB,
value & MyTypeC,
value & MyTypeD
);
// 输出结果:1, 2, 0, 0
这里我们再通过二进制解释一下:
转化成二进制:
MyTypeA: 0 0 0 1
|
MyTypeB: 0 0 1 0
|
MyTypeC: 0 1 0 0
|
MyTypeD: 1 0 0 0
----------------
value : 1 1 1 1
ps:以上的结果是通过|得到 value 的值(|的意思是只要有一个为1,结果就为1)
value : 1 1 1 1
&
MyTypeA: 0 0 0 1
----------------
结果值: 0 0 0 1
ps:0001就是 MyTypeA 的值
从结果可以看出:1 是 MyTypeA 的值,2 是 MyTypeB 的值,其它枚举值没有参与组合使用,值都为 0。这也说明,如果 value & MyTypeC 的值为 0,说明 value 不包含 MyTypeC,反之亦然。