iOS 枚举

开发中枚举是很常见的,系统框架频繁使用枚举去定义状态码,选项,让我们看到了他在特定场景下的优势。

常见的枚举

枚举在开发中很常见,如用来表示状态,类似于表示一个错误状态可以用如下枚举

typedef NS_OPTIONS(NSInteger, ErrorType) {
    ERR_UNKNOWN                         = -1,// 未知错误
    ERR_INIT_NETWORK                    = -2,// 初始化网络失败
    ERR_INVALID_SESSION                 = -3,// 无效的会话ID
    ERR_CONNECT                         = -4,// 网络连接失败
};

这种表示状态的枚举 编译器会为枚举分配一个独有的编号,默认从0开始,每个枚举递增1,也可以自定义枚举的值,不过也是具有唯一性。

位移枚举

在cocoa框架中,可以发现系统频繁的使用位移枚举。如:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {    二进制值    十进制
    UIViewAutoresizingNone                 = 0,         0000 0000  0
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,    0000 0001  1
    UIViewAutoresizingFlexibleWidth        = 1 << 1,    0000 0010  2
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,    0000 0100  4
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,    0000 1000  8
    UIViewAutoresizingFlexibleHeight       = 1 << 4,    0001 0000  16
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5     0010 0000  32
};

这么定义的好处是可以组合使用,这种设计很巧妙, 我们来分析下 UIViewAutoresizingFlexibleWidth| UIViewAutoresizingFlexibleHeight 是怎么组合的。

位移位运算

位移位运算用来表示枚举值。运算规则为:将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。通过按位运算可以保证每个枚举值所对应的二进制表示中,只有1个二进制位的值是1

// 通过按位运算符得出他们的二进制值
UIViewAutoresizingFlexibleWidth         1 << 1,    0000 0010
UIViewAutoresizingFlexibleHeight        1 << 4,    0001 0000

按位或运算符(|)

按位或运算符用来组合枚举值,运算规则为:参加运算的两个二进制对应数位只要有一个为1,其值为1。

// 使用时通过|来组合
UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight 
0000 0010
0001 0000
// 运算后得出
0001 0010

按位与运算符(&)

按位与运算符用来判断枚举选项。运算规则为:两对应数位同时为“1”,结果才为“1”,否则为0

// 使用时用对&amp;枚举值判断
UIViewAutoresizing type = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
if (type &amp; UIViewAutoresizingFlexibleWidth) { 
    // 0001 0010 &amp; 0000 0010 == 0000 0010 得出结果
    UIViewAutoresizingFlexibleWidth
}
if (type &amp; UIViewAutoresizingFlexibleHeight) { 
    // 0001 0010 &amp; 0001 0000 == 0001 0000 得出结果
    UIViewAutoresizingFlexibleHeight
}

枚举扩展性

1.字符串类型枚举

某些场景下,我们定义枚举其实最后都是转成字符串用的,我们需要在定义时解决后续使用问题可以这么操作

比如一个错误状态

typedef NS_OPTIONS(NSInteger, ErrorType) {
    ERR_UNKNOWN                         = -1,// 未知错误
    ERR_INIT_NETWORK                    = -2,// 初始化网络失败
    ERR_INVALID_SESSION                 = -3,// 无效的会话ID
    ERR_CONNECT                         = -4,// 网络连接失败
    ERR_INVALID_ACCESS                  = -5,// 拒绝访问
    ERR_PEER_OFFLINE                    = -6,// 对方不在线
    ERR_SESSION_TYPE                    = -7,// 错误的会话ID
    ERR_TIME_OUT                        = -8,// 超时
};

// 定义枚举字符串值
NSString *GetErrorDesc(ErrorType type) {
   switch (type) {
        case ERR_UNKNOWN:
            return @"未知错误";
        case ERR_INIT_NETWORK:
            return @"初始化网络失败";
        case ERR_INVALID_SESSION:
            return @"无效的会话ID";
        case ERR_CONNECT:
            return @"网络连接失败";
        case ERR_INVALID_ACCESS:
            return @"拒绝访问";
        case ERR_PEER_OFFLINE:
            return @"对方不在线";
        case ERR_SESSION_TYPE:
            return @"错误的会话ID";
        case ERR_TIME_OUT:
            return @"超时";
        default:
            return @"";
    }
}

使用时弹框可以直接

 NSString *errorDesc = GetErrorDesc(ERR_CONNECT);

2.双向映射关系的枚举

这里以建立如下映射关系为例

OPREATE_UNKNOWN <———> unknown

OPREATE_START   <———> start

OPREATE_END      <———> end

typedef NS_OPTIONS(NSUInteger, OperateType) {
    OPREATE_UNKNOWN           = 0, // 未知操作
    OPREATE_START                   , // 开始
    OPREATE_END                  , // 结束
};

// 创建初始化函数。等于用宏创建一个getter函数
#define OperateArray [NSMutableArray arrayWithObjects:@"unknown",@"start", @"end", nil]
// 枚举 to 字串
#define OperateTypeString(type) ([OperateArray objectAtIndex:type])
// 字串 to 枚举
#define OperateTypeEnum(string) ([OperateArray indexOfObject:string])

使用时即可以获取相互转化

NSString *op_string = OperateTypeString(OPREATE_START);// start
OperateType op_enum = OperateTypeEnum(@"start"); // OPREATE_START