枚举,enum,C语言特性。
由于Objective-C基于C语言,所以也有enum。
其实在阅读API或者系统框架时候经常会看到此类型。但在实际开发中,我们往往会忽视它的作用。在一系列常量来表示错误状态、类型、可组合选项等得时候,我们均可使用枚举为其命名。
枚举,其实只是一种常量命名的方式。
它是一个整形(int) ,一般是4个字节的int值,在64位系统上是8个字节。并且,它不参与内存的占用和释放,枚举定义变量即可直接使用,不用初始化。在代码中使用枚举的目的有一个,那就是增加代码的可读性。
主要有三种方式:
1、enum
这是C语言风格,例如:
enum{
TypeA ,
TypeB,
TypeC,
};
typedef enum{
TypeA ,
TypeB,
TypeC,
}TypeName;
数据枚举的顺序规定了枚举数据的序号,从0开始,依次递增。 TypeA=0,TypeB=1,TypeC=2。我们还可以从某个值开始或者全部指定值,例如:
enum{
TypeA = 3 ,
TypeB,
TypeC,
};
//此时TypeB=4,TypeC=5。
2、NS_ENUM 、NS_OPTIONS
OC中常见的枚举,例如常见的:
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
UIViewAnimationCurveEaseInOut, // slow at beginning and end
UIViewAnimationCurveEaseIn, // slow at beginning
UIViewAnimationCurveEaseOut, // slow at end
UIViewAnimationCurveLinear
};
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
UIViewAnimationOptionLayoutSubviews = 1 << 0,
UIViewAnimationOptionAllowUserInteraction = 1 << 1, // turn on user interaction while animating
UIViewAnimationOptionBeginFromCurrentState = 1 << 2, // start all views from current value, not initial value
UIViewAnimationOptionRepeat = 1 << 3, // repeat animation indefinitely
UIViewAnimationOptionAutoreverse = 1 << 4, // if repeat, run animation back and forth
UIViewAnimationOptionOverrideInheritedDuration = 1 << 5, // ignore nested duration
UIViewAnimationOptionOverrideInheritedCurve = 1 << 6, // ignore nested curve
UIViewAnimationOptionAllowAnimatedContent = 1 << 7, // animate contents (applies to transitions only)
UIViewAnimationOptionShowHideTransitionViews = 1 << 8, // flip to/from hidden state instead of adding/removing
UIViewAnimationOptionOverrideInheritedOptions = 1 << 9, // do not inherit any options or animation type
UIViewAnimationOptionCurveEaseInOut = 0 << 16, // default
UIViewAnimationOptionCurveEaseIn = 1 << 16,
UIViewAnimationOptionCurveEaseOut = 2 << 16,
UIViewAnimationOptionCurveLinear = 3 << 16,
UIViewAnimationOptionTransitionNone = 0 << 20, // default
UIViewAnimationOptionTransitionFlipFromLeft = 1 << 20,
UIViewAnimationOptionTransitionFlipFromRight = 2 << 20,
UIViewAnimationOptionTransitionCurlUp = 3 << 20,
UIViewAnimationOptionTransitionCurlDown = 4 << 20,
UIViewAnimationOptionTransitionCrossDissolve = 5 << 20,
UIViewAnimationOptionTransitionFlipFromTop = 6 << 20,
UIViewAnimationOptionTransitionFlipFromBottom = 7 << 20,
} NS_ENUM_AVAILABLE_IOS(4_0);
这两个宏的定义在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)。
什么时候需要用到NS_OPTIONS呢?
当枚举变量可能要代表多个枚举值的时候。引用网上说法就是“其实给一个枚举变量赋予多个枚举值的时候,原理只是把各个枚举值加起来。当加起来以后,就获取了一个新的值,那么为了保证这个值的唯一性,这个时候就体现了位运算的重要作用,位运算可以确保枚举值组合的唯一性,因为位运算的计算方式是将二进制转换成十进制,也就是说,枚举值里面存取的是计算后的十进制值。”
还有就是在定义选项的时候,并且这些选项可以彼此组合。只要枚举定义得对,各选项之间就可通过“按位或操作符”(bitwise OR operator)来组合。例如,iOS UI框架中有如下枚举类型,用来表示某个视图应该如何在水平或垂直方向上调整大小:
enum UIViewAutoresizing {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5,
}
每个选项均可启用或禁用,使用上述方式来定义枚举值即可保证这一点,因为在每个枚举值所对应的二进制表示中,只有1个二进制位的值是1。用“按位或操作符”可组合多个选项,例如:UIViewAutoResizingFlexibleWidth| UIViewAutoresizingFlexibleHeight。下图中列出了每个枚举成员的二进制值,并演示了刚才那两个枚举组合之后的值。用“按位与操作符”(bitwise AND operator)即可判断出是否已启用某个选项:
enum UIViewAutoresizing resizing =
UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight;
if (resizing & UIViewAutoresizingFlexibleWidth) {
// UIViewAutoresizingFlexibleWidth is set
}
枚举使用中的注意事项:
1、应该用枚举来表示状态机的状态、传递给方法的选项以及状态码等值,给这些值起个易懂的名字。
2、如果把传递给某个方法的选项表示为枚举类型,而多个选项又可同时使用,那么就将各选项值定义为2的幂,以便通过按位或操作将其组合起来。
3、用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
4、在处理枚举类型的switch语句中不要实现default分支。这样的话,加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举。