iOS 枚举

234 阅读5分钟

概述

iOS 中的枚举是一种常用的数据类型,可以帮助我们在编写代码时更好地组织和管理相关的常量值。在本文中,我们将从 OC 与 Swift 两个方向的出发,介绍枚举在 iOS 开发中的基础用法以及一些高级用法

1. OC 中的枚举

1.1 枚举的定义

OC 中的枚举可以通过 enum 关键字来定义,如下所示:

typedef enum {
    kGenderMale,
    kGenderFemale,
    kGenderUnknown
} Gender;

上述代码定义了一个枚举类型 Gender,其中包含了三个常量值:kGenderMalekGenderFemalekGenderUnknown。这些常量值都被默认赋予整数值,起始值为 0,依次递增。

在使用枚举时,可以直接通过枚举常量值来获取其对应的整数值,例如:

Gender gender = kGenderMale;
int intValue = gender; // intValue = 0

也可以直接将整数值赋给枚举变量,例如:

Gender gender = 1; // gender = kGenderFemale

1.2 位移枚举

除了普通枚举之外,OC 还提供了一种特殊的枚举类型,称之为“位移枚举(Option Set)”。位移枚举可以表示一组状态,每个状态都是独立的,可以通过按位或(|)运算进行组合。

例如,下面的代码定义了一个 UIViewAutoresizing 的位移枚举类型,表示 UIView 自动调整大小时可以采用的一组可选项:

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
    UIViewAutoresizingNone                 = 0,
    UIViewAutoresizingFlexibleLeftMargin   = 1 << 0,
    UIViewAutoresizingFlexibleWidth        = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin  = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin    = 1 << 3,
    UIViewAutoresizingFlexibleHeight       = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};

在使用位移枚举时,可以使用按位或(|)运算符将多个枚举常量组合起来,例如:

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

2. Swift 中的枚举

2.1 枚举的定义

在 Swift 编程语言中,枚举是一种很有用的数据类型,可以用来表示一组相关联的值。其在 Swift 中有许多高级特性,如原始值、关联值以及嵌套枚举等

2.2 枚举的原始值

Swift 中的枚举可以包含原始值,原始值可以是任何一种数据类型,如整型、浮点型等。

例如,下面的代码定义了一个用于表示请求方式的 Enum 类型:

/// 为 RequestMethod 枚举指定字符串类型的原始值
enum RequestMethod: String {
    case get         = "get"
    case post        = "post"
    case upload      = "upload"
    case download    // 等价于 download = "download"
}

对于 String 类型的 Raw Value,若没指定值,默认为 case name,

对于 Int/Float 类型,默认值从 0 开始,依次 +1

通过 rawValue 属性可以获取 case 对应的 原始值

let value = RequestMethod.get.rawValue

2.3 枚举的关联值

Swift 中的枚举可以包含关联值,关联值可以为枚举成员提供更多的信息,且可为关联值提供默认值,例如:

enum Shape {
    /// 圆形
    case circle(radius: Float = 5.0)
    /// 矩形
    case rectangle(width: Float, height: Float)
    /// 正方形
    case square(side: Float)
}

// 创建一个 Shape 枚举变量,并指定其为圆形,半径为 5
let shape = Shape.circle(radius: 15)

在这个例子中,枚举 Shape包含三个不同的枚举值,分别是:

  • circle:表示一个圆形,其关联值 radius 表示圆的半径,并提供默认值
  • rectangle:表示一个矩形,其关联值 widthheight 分别表示矩形的宽度和高度
  • square:表示一个正方形,其关联值 side 表示正方形的边长

这种使用关联值的方式可以使枚举类型更加灵活,能够表示更加复杂的数据结构。在实际使用中,可以根据具体需求选择不同的关联值类型,并进行相关的处理。

2.4 枚举的遍历

有时,我们希望遍历 Enum 的所有 cases,或是获取第一个 case,此时 CaseIterable 派上用场了

public protocol CaseIterable {

    /// A type that can represent a collection of all values of this type.    
    associatedtype AllCases : Collection = [Self] where Self == Self.AllCases.Element 
   
    /// A collection of all values of this type.    
    static var allCases: Self.AllCases { get }
}

CaseIterable协议中,associatedtype 关键字用于声明一个关联类型,让遵循该协议的类型来指定该类型的具体实现。其中,AllCases 就是一个关联类型,它被声明为一个集合类型,默认值为 [Self],也就是一个由遵循该协议的类型本身组成的数组。

此外,where 语句也可以对关联类型进行约束,限制遵循该协议的类型的实现方式。在这里,where 语句对 AllCases 进行了两个约束条件:

  • Self == Self.AllCases.Element:表示 SelfSelf.AllCases.Element 这两个类型必须相等,也就是说 Self 本身就是集合类型中的元素类型。
  • Self.AllCases 必须是 Collection 协议的遵循者:这个约束条件表示 AllCases 必须是一个集合类型,并且遵循 Collection 协议。

总体而言,AllCases 是一种在枚举类型中常用的关联类型。通过使用 AllCases,我们可以方便地遍历枚举类型中的所有成员,并以数组的形式访问它们。

enum MyEnum: String, CaseIterable {
    case case1 = "case1"
    case case2
    case case3
}

let case1 = MyEnum.allCases.first
for value in MyEnum.allCases {
    print(value)
}

注意:对于有关联值的枚举,不会自动合成 allCases,因为关联值没法确定,此时,需要手动实现 CaseIterable 协议

2.5 嵌套枚举

Swift 中的嵌套枚举可以将一个枚举类型定义在另一个枚举类型的内部,从而形成更加复杂和有层次的枚举结构。下面是一个简单的示例:

enum Family {
    case father(name: String)
    case mother(name: String)
    
    enum Child {
        case son(name: String, age: Int)
        case daughter(name: String, age: Int)
    }
}

let parents = Family.father(name: "XXX")
let child = Family.Child.son(name: "XXX", age: 8)

在这个例子中,Family 是一个嵌套枚举类型,它包含了两个枚举值 fathermother,每个值都带有一个关联值,表示家庭中的父亲和母亲。此外,Family 还定义了一个名为 Child 的嵌套枚举类型,该类型表示家庭中的孩子,具有两个不同的枚举值 sondaughter,每个值都带有两个关联值,分别表示孩子的姓名和年龄。

可以看到,在 Swift 中使用嵌套枚举可以使枚举类型更加灵活和具有层次感,能够更好地表达复杂的数据结构

参考

docs.swift.org/swift-book/…