最近看了一本OC进阶的书,很多人推荐的Effective Objictive-C2.0,看到书中枚举类型的介绍,觉得很不错,这里为大家总结一下。
enum
由于Objective-C基于C语言,所以C语言有的功能它都有,其中之一就是枚举类型enum。枚举类型只是一种常亮命名方式,某个对象所经历的各种状态或者类型就可以定义为一个简单的枚举类型,比如一个通讯录或者聊天页的页面有不同的会话类型,根据类型的不同所展示的页面或者操作对应也不相同。可以简单的如下定义枚举类型:
enum ViewType {
Contacts_Stranger,//陌生人
Contacts_NormalFriend,//普通好友
Contacts_SpecialFriend,//特别关心好友
};
由于每种状态都用一个便于理解的值来表示,所以这样写更为直观,代码更易读懂。编译器会为枚举分配一个独有的编号,默认从0开始,每个枚举递增1。
然而定义枚举类型的方式却不太简洁,要依如下语法编写:
enum ViewType type = Stranger;
typedef enum
使用typedef来定义枚举类型则简洁很多:
enum ViewType {
Contacts_Stranger,//陌生人
Contacts_NormalFriend,//普通好友
Contacts_SpecialFriend,//特别关心好友
};
typedef enum ViewType ViewType;
或者这样定义:
typedef enum {
Contacts_Stranger,//陌生人
Contacts_NormalFriend,//普通好友
Contacts_SpecialFriend,//特别关心好友
}ViewType;
就可以用简写的ViewType代替 enum ViewType了。
还可以不使用编译器所分配的序号,而是手工指定某个枚举成员所对应的值,语法如下:
enum ViewType {
Contacts_Stranger = 1,//陌生人
Contacts_NormalFriend,//普通好友
Contacts_SpecialFriend,//特别关心好友
};
上述代码把Contacts_Stranger的值设为1,那么接下来的几个枚举值会在上一个的基础上递增1,则Contacts_SpecialFriend的值为3。
位移操作枚举定义
还有一种情况应该使用枚举类型,那就是定义选项的时候,若这些选项可以彼此组合,则更应如此,个选项之间可以通过“按位或操作符”来组合。例如,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 << 2’表示1左移2位,即为二进制100。
每个选项均可启用或者禁用,使用上述枚举定义即可保证这一点,因为上述每个枚举值中只有一个二进制位为1。用“按位或操作符”可组合多个选项,比如:
enum UIViewAutoresizing resizing = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
if (resizing & UIViewAutoresizingFlexibleWidth) {
//UIViewAutoresizingFlexibleWidth is set
}
系统库中频繁使用这个方法。iOS UI框架中的UIKit里还有个例子,用枚举告诉系统视图所支持的设备显示方向。这个枚举类型叫做UIInterfaceOrientationMask,开发者需要实现一个名为supportedInterfaceOrientations 方法,将视图所支持的显示方向告诉系统:
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
}
此外,一些小于等于三个的枚举值,可以不用位移操作枚举定义一样也可以这样使用,因为三个枚举值正好是0,1,2。例如系统UITableView中的tableView编辑类型的枚举类型定义:
typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) {
UITableViewCellEditingStyleNone,
UITableViewCellEditingStyleDelete,
UITableViewCellEditingStyleInsert
};
在tableView的代理方法中依然可以“按位或操作符”来高速系统编辑样式:
- ( UITableViewCellEditingStyle )tableView:( UITableView *)tableView editingStyleForRowAtIndexPath:( NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
}
但如果我们自己定义,还是规范的用位移操作枚举定义比较好。
NS_ENUM、NS_OPTIONS
你可能发现上面的枚举类型的定义和我们之前讲的有些不一样,出现了NS_ENUM这个关键字,并且格式也有些不同。这是因为Foundation框架中定义了一些辅助的宏(宏的介绍请看这里:http://blog.youkuaiyun.com/liu1347508335/article/details/50824946)。用这些宏来定义枚举类型时,可以指定用于保存枚举值的底层数据类型。这些宏是是用#define预处理指令来定义的,其中一个用于定义像ViewType这种普通的枚举类型,另一个用于定义像UIViewAutoresizing这种包含一些列选项的枚举类型,其用法如下:
typedef NS_ENUM(NSUInteger, ViewType) {
Contacts_Stranger,//陌生人
Contacts_NormalFriend,//普通好友
Contacts_SpecialFriend,//特别关心好友
};
typedef NS_OPTIONS(NSUInteger, PermittedDirection) {
PermittedDirectionUp = 1 << 0,
PermittedDirectionDown = 1 << 1,
PermittedDirectionLeft = 1 << 2,
PermittedDirectionRight = 1 << 3,
};
这两个宏的具体实现就不多介绍了,感兴趣的可以去看一看。用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
还有一点需要注意,当switch语句中应用枚举类型时,最好去掉default分支。这样的话,如果稍后又加了一种状态,那么编译器就会发出警告信息,提示新加入的状态并未在switch分支中处理。。假如写上了default分支则不会发出警告。通常要确保switch语句能正确处理所有枚举样式。
总结
应该用枚举来表示状态机的状态、传递给方法的选项以及状态码等值,给这些值起个易懂的名字。
如果把传递给某个方法的选项表示为枚举类型,而多个选项又可同时使用,那么就将各选项值定义为2的幂,以便通过按位或操作将其组合起来。
用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。
在处理枚举类型的switch语句中不要实现default分支。