美文网首页
《Effective Objective-C 2.0 》 阅读笔

《Effective Objective-C 2.0 》 阅读笔

作者: dibadalu | 来源:发表于2016-03-05 16:53 被阅读107次

    第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分支,并确保有所有可能出现的情况。

    要点

    • 应该用枚举来表示状态机的状态传递给方法的选项以及状态码等值,给这些值起个易懂的名字。
    • 如果把传递给某个方法的选项表示为枚举类型,而多个选项又可同时使用,那么久将各选项值定义为2的幂,以便通过按位或操作将其组合起来。
    • NS_ENUMNS_OPTIONS宏来定义枚举类型,并指明其底层数据类型。这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型。
    • 在处理枚举类型的switch语句中不要实现default分支。这样的话,加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举。

    参考文献

    NS_ENUM & NS_OPTIONS
    位操作 维基百科

    相关文章

      网友评论

          本文标题:《Effective Objective-C 2.0 》 阅读笔

          本文链接:https://www.haomeiwen.com/subject/bztakttx.html