You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何通过switch匹配外层枚举获取对应嵌套Enum的allCases

问题原因

你的代码无法正常运行核心是三个问题:

  • 定义的UnitProtocol是空协议,没有约定实现类必须提供allCases、rawValue属性,编译器无法判定遵守协议的类型是否支持遍历、是否能取到展示用的文本值。
  • 各嵌套单位枚举(Temperature/Length/Time/Volume)是完全独立的具体类型,你原来的计算属性返回UnitProtocol类型会触发类型擦除,无法直接传递给ForEach做遍历;且你返回的是枚举元类型(Units.Temperature.Type),不是可遍历的实例集合。
  • 给具体单位选择器绑定的$units是外层单位大类的枚举类型,和内层具体单位的类型完全不匹配,无法做选择值绑定。
实现方案

不需要推翻你现有的嵌套枚举结构,只需要做几处调整即可:

  1. 补全UnitProtocol的能力约定,要求所有遵守协议的单位类型必须支持遍历、拥有String类型的rawValue
  2. 拆分状态:单独定义单位大类、源单位、目标单位三个状态,其中具体单位用String类型存储rawValue,解决不同类型单位无法统一存储的问题
  3. 用计算属性直接返回当前大类对应的具体单位字符串数组,统一遍历元素的类型,避免元类型、类型擦除带来的问题
  4. 增加大类切换的回调,切换大类时自动重置默认选中的具体单位,避免逻辑异常

第一步:调整协议与枚举定义

// 协议约定所有单位类型必须支持遍历、rawValue为String类型
protocol UnitProtocol: CaseIterable, RawRepresentable where RawValue == String {}

enum Units: String, CaseIterable {
  case temperature, length, time, volume
  // 所有嵌套具体单位枚举遵守改造后的UnitProtocol
  enum Temperature: String, UnitProtocol {
    case celsius, fahrenheit, kelvin
  }
  enum Length: String, UnitProtocol {
    case meters, kilometers, feet, yards, miles
  }
  enum Time: String, UnitProtocol {
    case seconds, minutes, hours, days
  }
  enum Volume: String, UnitProtocol {
    case milliliters, liters, cups, pints, gallons
  }
}

第二步:调整视图逻辑

struct ContentView: View {
  // 当前选中的单位大类
  @State private var selectedCategory = Units.temperature
  // 选中的源转换单位、目标转换单位,用rawValue字符串统一存储
  @State private var sourceUnit = ""
  @State private var targetUnit = ""

  // 返回当前大类对应的所有具体单位,统一为[String]类型,可直接给ForEach遍历
  private var availableUnits: [String] {
    switch selectedCategory {
    case .temperature:
      return Units.Temperature.allCases.map(\.rawValue)
    case .length:
      return Units.Length.allCases.map(\.rawValue)
    case .time:
      return Units.Time.allCases.map(\.rawValue)
    case .volume:
      return Units.Volume.allCases.map(\.rawValue)
    }
  }

  var body: some View {
    NavigationView {
      Form {
        Section {
          Picker("Units to convert", selection: $selectedCategory) {
            ForEach(Units.allCases, id: \.self) {
              Text($0.rawValue.capitalized)
            }
          }
          // 切换大类时重置默认选中的具体单位
          .onChange(of: selectedCategory) { _ in
            sourceUnit = availableUnits.first ?? ""
            targetUnit = availableUnits.first ?? ""
          }
        }

        Section {
          Picker("Convert from", selection: $sourceUnit) {
            ForEach(availableUnits, id: \.self) {
              Text($0.capitalized)
            }
          }
        }

        Section {
          Picker("Convert to", selection: $targetUnit) {
            ForEach(availableUnits, id: \.self) {
              Text($0.capitalized)
            }
          }
        }
      }
      .navigationTitle("Unit Converter")
      // 首次加载时初始化默认选中的单位
      .onAppear {
        sourceUnit = availableUnits.first ?? ""
        targetUnit = availableUnits.first ?? ""
      }
    }
  }
}
方案说明
  • 完全保留你原本设计的嵌套枚举结构,后续新增单位类型只需要新增对应嵌套枚举、在availableUnits的switch分支中加一行映射即可,维护成本很低
  • 所有遍历用的数组类型统一为[String],不存在类型不匹配、元类型无法遍历的编译问题
  • 选择器的绑定值类型和选中值类型完全对齐,不会出现绑定错误
  • 切换大类时自动重置选中值,不会出现选中值和当前展示列表不匹配的逻辑问题

内容的提问来源于stack exchange,提问作者hisikig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 06:09:21