iOS – OC和Swift中位移枚举(多选)的使用

本文记录iOS开发中位移枚举(NS_OPTIONS)的使用,以及在Swift中如何使用位移枚举。

在iOS开发中枚举有三种形式

typedef enum {
    XXTop,
    XXBottom
}XXDirection;


// 定义类型
typedef NS_ENUM(NSInteger, XXDirection) {
    XXTop,
    XXBottom
}


// 位移枚举
typedef NS_OPTIONS(NSUInteger, XXDirection) {
    XXTop       = 1 << 0,   // (2) 0000 0001, (10) 1
    XXBottom    = 1 << 1,   // (2) 0000 0010, (10) 2
    XXLeft      = 1 << 2,   // (2) 0000 0100, (10) 4
    XXRight     = 1 << 3,   // (2) 0000 1000, (10) 8
}

这篇文章将记录 第三种: 位移枚举的使用


使用

在位移枚举中用到了 <<, 当初并不知道这样做的用意, 因为最初在使用枚举的时候,往往只会使用一个枚举值。 但是很多场景要使用多个枚举值,即多选。例如下面场景

// 在SDWebImage下载图片时,需要 设置多个选项,例如这里需要 需要高优先级下载,也需要根据设备内存压缩下载的图片等。

[SDWebImageDownloader.sharedDownloader 
    downloadImageWithURL:url 
    options:SDWebImageDownloaderHighPriority | SDWebImageDownloaderScaleDownLargeImages 
    progress: nil 
    completed: nil];

1. ( << ) 位移符的使用

    XXBottom    = 1 << 1,   // (2) 0000 0010, (10) 2

m << n 表示在m的基础数值上左移n位,这里1的二进制为 0000 0001, 左移一位后是
0000 0001 -> 0000 0010
也就是变成了十进制的2。

在位移枚举中一般都采取这样的套路,每个枚举值都左移一位,
0000 0001
0000 0010
0000 0100
0000 1000

这种情况下使用多选操作时,就会很方便。

多选

多选操作会用到两个运算符, & 按位与| 按位或

这两个符号可以参考在 if 语句中 &&|| 的使用

所以:
1 & 1 = 1
1 & 0 = 0
0 & 0 = 0

与运算,有0必0

1 | 1 = 1
1 | 0 = 1
0 | 0 = 0

或运算,有1必1

所以在上述位移符的帮助下, 多选操作会变得简单,例如 我想设置XXTop和 XXBottom,

XXTop | XXBottom

    0000 0001 -> XXTop
OR  0000 0010 -> XXBottom
———————————————————————————
    0000 0011

同时可以使用 & 判断传入的多选值是否包括某个选项, 例如我要在上述 (XXTop | XXBottom) 中判断是否包含XXTopXXLeft

假设 options = (XXTop | XXBottom) = 0000 0011

判断是否含有XXTop: XXTop & options

    0000 0001 -> XXTop
AND 0000 0011 -> options
———————————————————————————
    0000 0001 -> XXTop   // 表示options中包含XXtop
    0000 0100 -> XXLeft
AND 0000 0011 -> options
———————————————————————————
    0000 0000 -> 0   // 表示options中不包含XXLeft

Swift中位移枚举的使用

Swift中给出的替换方案是 选项集合(OptionSet), 例如上述XXDirection在Swift中可以改写成:

struct XXDirection: OptionSet {
    let rawValue: UInt
    
    static let top = XXDirection(rawValue: 1 << 0)
    static let bottom = XXDirection(rawValue: 1 << 1)
    static let left = XXDirection(rawValue: 1 << 2)
    static let right = XXDirection(rawValue: 1 << 3)
}

在Swift就不再使用 &, | 运算了, 如果想使用多选,需要用数组代替,例如

let options: XXDirection = [.top, .bottom]  // 与OC中 XXTop | XXBottom 相同的作用

判断是否包含某个值时用 .contaions() 方法即可。

let options: XXDirection = [.top, .bottom]

options.contains(.top)  // true, 包含top

options.contains(.left) // false, 不包含left