《Effective Objective-C 2.0 》 阅读笔

2016-03-05  本文已影响107人  dibadalu

第5条:用枚举表示状态、选项、状态码

1. 枚举类型的定义

枚举只是一种常量命名方式。某个对象所经历的各种状态就可以定义为一个简单的枚举集(编译器会为枚举集里的枚举各自分配一个独有的编号,从0开始,每个枚举递增1)。
然而,定义枚举变量的方式并不简洁:

// 声明一个名为EOCConnectionState的枚举
enum EOCConnectionState{
    EOCConnectionStateDisconnected,
    EOCConnectionStateConnecting,
    EOCConnectionStateConnected,
};
// 定义一个名为state的枚举变量
enum EOCConnectionState state = EOCConnectionStatedDisconnected;

可以通过typedef关键字重新定义枚举类型:

// 声明一个名为EOCConnectionState的枚举
enum EOCConnectionState{
    EOCConnectionStateDisconnected,
    EOCConnectionStateConnecting,
    EOCConnectionStateConnected,
};
// 通过typedef给enum EOCConnectionState起别名EOCConnectionState
typedef enum EOCConnectionState EOCConnectionState;
// 定义一个名为state的枚举变量
EOCConnectionState state = EOCConnectionStateDisconnected;

2. 指定枚举的底层数据类型

通过指定枚举的底层数据类型,可以向前声明枚举类型。如果编译器不清楚底层数据类型的大小,则在用到此枚举类型时,就不知道究竟该给变量分配多少空间。

*** 指定底层数据类型的语法 ***

enum EOCConnectionStateConnectionState : NSInteger {}; 

*** 在向前声明时指定底层数据类型的语法 ***

enum EOCConnectionStateConnectionState : NSInteger; 

3. 枚举类型的其他用法

*** 3.1 手动指定某个枚举成员所对应的值 ***

enum EOCConnectionStateConnectionState {
    EOCConnectionStateDisconnected = 1,
    EOCConnectionStateConnecting,
    EOCConnectionStateConnected,
}; 

EOCConnectionStatedDisconnected的值设为1,此后每个枚举的值递增1。

*** 3.2 选项 ***

/*  UI框架中的UIViewAutoresizing枚举类型  */
enum {
   UIViewAutoresizingNone                 = 0,
   UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
   UIViewAutoresizingFlexibleWidth        = 1 << 1,
   UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
   UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
   UIViewAutoresizingFlexibleHeight       = 1 << 4,
   UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
typedef NSUInteger UIViewAutoresizing;

/*  UI框架中的UIInterfaceOrientationMask枚举类型  */
typedef enum : NSUInteger {
   UIInterfaceOrientationMaskPortrait = (1 << UIInterfaceOrientationPortrait ),
   UIInterfaceOrientationMaskLandscapeLeft = (1 << UIInterfaceOrientationLandscapeLeft ),
   UIInterfaceOrientationMaskLandscapeRight = (1 << UIInterfaceOrientationLandscapeRight ),
   UIInterfaceOrientationMaskPortraitUpsideDown = (1 << UIInterfaceOrientationPortraitUpsideDown ),
   UIInterfaceOrientationMaskLandscape =
   (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight ),
   UIInterfaceOrientationMaskAll =
   (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
   UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown ),
   UIInterfaceOrientationMaskAllButUpsideDown =
   (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft |
   UIInterfaceOrientationMaskLandscapeRight ),
} UIInterfaceOrientationMask;

每个选项均可启用或禁用。用“按位或操作符”(“|”)可组合多个选项,而用“按位与操作符”(“&”)可判断出是否已启用某个选项。

*** 3.3 Foundation框架中辅助的宏——NS_ENUM和NS_OPTIONS ***
Foundation框架中定义了一些辅助的宏,用这些宏来定义枚举类型时,也可以指定用于保存枚举值的底层数据类型。这些宏是用#define预处理指令来定义的,其中,NS_ENUM用于定义像EOCConnectionState这种普通的枚举类型,而NS_OPTIONS用于定义像UIViewAutoresizing这种可以通过“按位或操作符”来组合选项的枚举类型。

如:

/* NS_ENUM (所指定的底层数据类型, 枚举类型名称) */
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    UITableViewCellStyleDefault,
    UITableViewCellStyleValue1,
    UITableViewCellStyleValue2,
    UITableViewCellStyleSubtitle
};

/* NS_OPTIONS (所指定的底层数据类型, 枚举类型名称) */
typedef NS_OPTIONS(NSUInteger, EOCPermittedDirection) {
    EOCPermittedDirectionUp      = 1 << 0,
    EOCPermittedDirectionDown    = 1 << 1,
    EOCPermittedDirectionLeft    = 1 << 2,
    EOCPermittedDirectionRight   = 1 << 3,
};

NS_OPTIONS的定义若按C++模式编译,由于作为选项的枚举值经常需要用按位或运算来组合,所以想编译代码,需要将按位或操作的结果显示转换为枚举类型本身(EOCPermittedDirection)。
如:

EOCPermittedDirection permittedDirections = (EOCPermittedDirection)EOCPermittedDirectionUp | EOCPermittedDirectionLeft;

*** 3.4 状态码 ***
可以把逻辑含义相似的一组状态码放入同一个枚举集里,而不用#define预处理指令或常量来定义。

*** 3.5 样式 ***
创建某个UI元素时可以使用不同的样式,在这种情况下,最应该把样式声明为枚举类型。

*** 3.6 在switch语句里 ***

typedef NS_ENUM(NSUInteger, EOCConnectionState){
    EOCConnectionStateDisconnected,
    EOCConnectionStateConnecting,
    EOCConnectionStateConnected,
};

switch (_currentState){
    EOCConnectionStateDisconnected:
        // 实现代码
        break;
    EOCConnectionStateConnecting:
        // 实现代码
        break;
    EOCConnectionStateConnected:
        // 实现代码
        break;
}

若是用枚举来定义状态机(state machine),则最好不要有default分支,并确保有所有可能出现的情况。

要点

参考文献

NS_ENUM & NS_OPTIONS
位操作 维基百科

上一篇下一篇

猜你喜欢

热点阅读