Swift 生成枚举集合的CaseIterable协议
Swift 生成枚举集合的CaseIterable协议

Swift 生成枚举集合的CaseIterable协议

CaseIterable 是 Swift 标准库中的一个协议,用于自动生成枚举中所有可能的值集合。它非常适合用来处理需要遍历枚举值的场景,例如在 Picker 中显示选项列表,或者在循环中遍历所有枚举值。

协议定义

CaseIterable 定义如下:

protocol CaseIterable {
    associatedtype AllCases: Collection where Self.AllCases.Element == Self
    static var allCases: Self.AllCases { get }
}

核心功能

提供一个静态属性 allCases,返回枚举中所有可能值的集合。

如何让枚举遵循 CaseIterable

1、自动生成 allCases 属性

当枚举不包含关联值时,Swift 会自动为其生成 allCases 属性。

enum Direction: CaseIterable {
    case north
    case south
    case east
    case west
}

// 自动生成的 allCases:
// Direction.allCases == [Direction.north, Direction.south, Direction.east, Direction.west]

2、带原始值的枚举

包含原始值(如 String 或 Int)的枚举仍然可以自动支持 CaseIterable。

enum Fruit: String, CaseIterable {
    case apple = "Apple"
    case banana = "Banana"
    case cherry = "Cherry"
}

// Fruit.allCases == [Fruit.apple, Fruit.banana, Fruit.cherry]

3、手动实现 allCases

如果枚举有关联值,则需要手动实现 allCases 属性。

这是因为关联值使得枚举的所有可能性无法被自动推导。

enum Shape: CaseIterable {
    static var allCases: [Shape] = [.circle, .square]
    
    case circle
    case square
    case rectangle(width: Double, height: Double)
}

使用场景

1、遍历枚举所有值

enum Day: CaseIterable {
    case monday, tuesday, wednesday, thursday, friday, saturday, sunday
}

for day in Day.allCases {
    print(day)
}

输出

monday
tuesday
wednesday
thursday
friday
saturday
Sunday

2、在 SwiftUI 中生成选项列表

struct ContentView: View {
    @State private var selectedDay: Day = .monday

    var body: some View {
        Picker("Select a Day", selection: $selectedDay) {
            ForEach(Day.allCases, id: \.self) { day in
                Text(day.displayName).tag(day)
            }
        }
        .pickerStyle(.segmented)
    }
}

enum Day: String, CaseIterable {
    case monday, tuesday, wednesday, thursday, friday, saturday, sunday

    var displayName: String {
        rawValue.capitalized
    }
}

效果

一个选择器,显示所有天数供用户选择。

3、用作数据驱动

enum PaymentMethod: CaseIterable {
    case creditCard, paypal, applePay

    var description: String {
        switch self {
        case .creditCard: return "Credit Card"
        case .paypal: return "PayPal"
        case .applePay: return "Apple Pay"
        }
    }
}

let methods = PaymentMethod.allCases.map { $0.description }
print(methods) // ["Credit Card", "PayPal", "Apple Pay"]

注意事项

1、关联值限制

带关联值的枚举无法自动实现 allCases,需要手动提供。

2、大型枚举性能

allCases 返回的是一个数组,对非常大的枚举使用时可能会带来性能开销。

总结

CaseIterable 是用于遍历枚举所有可能值的强大工具,尤其在 SwiftUI 和数据驱动场景中非常常用。

自动支持无关联值的枚举;对于有关联值的枚举,需要手动实现。

搭配 ForEach 和 Picker 可以简化代码,提高可读性和开发效率。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注