繁体   English   中英

Swift:如何访问枚举的变量元素?

[英]Swift: How to access variable element of an enum?

几个小时以来,我一直在努力获取枚举的可变元素。

Swifticons-pod为我提供了以下枚举:

public enum WeatherType: Int {
    static var count: Int {
        return weatherIcons.count
    }

    public var text: String? {
        return weatherIcons[rawValue]
    }

    case alien, barometer, celsius, owm300, owm301, owm302, and200moreOfTheseNames
}

private let weatherIcons = ["\u{f075}", "\u{f079}", and202moreOfTheseFontCharacters]

从一个外部API( openWeatherMap.org ),我仅获得一个天气代码(比如说“ 300”),并且我想访问图标“ owm300”。

但是,如何在不知道rawValue的情况下访问枚举的此元素(即-198)?

我想到的最简单的方法之一就是创建某种映射字典,在其中您可以跟踪天气响应代码和它映射到的WeatherType,

let weatherCodeMapping: [Int: WeatherType] = [300: .owm300,
                                              301: .owm301,
                                              302: .owm302]

有了这个,您就不需要知道任何特定的rawValue,只需通过以下方式获取代码,

 let weatherType = weatherCodeMapping[weatherCode]

然后根据weatherType为图像创建其他映射。

let weatherIcon = weatherIconMapping[weatherType]

或直接从天气代码到图标创建单个映射。

这是计划:

  1. 我们需要列举所有枚举案例。 我们将通过遍历原始值来做到这一点(幸运的是, WeatherTypeInt支持)。
  2. 我们将存储延迟初始化的字典,该字典将String映射到WeatherType
  3. 最后,我们声明一个静态函数,该函数返回一个可选的WeatherType? 因为我们会遇到一个未知值。

这是代码:

extension WeatherType {
  // just some little convenience
  private typealias W = WeatherType

  // 1. define the sequence of all cases
  private static func allCases() -> AnySequence<W> {
    return AnySequence { () -> AnyIterator<W> in
      var raw = 0
      return AnyIterator {
        // Iterates while raw value can be converted to an enum case
        if let next = W(rawValue: raw) {
          raw += 1
          return next
        }
        return nil
      }
    }
  }

  // 2. Static properties are lazy so we'll use them to store the dictionary with String to WeatherType mapping
  private static let typeMap = W.allCases().reduce([String: W]()) { acc, next in
    var acc = acc
    acc[String(describing: next)] = next
    return acc
  }

  // 3. Declare the mapping function
  static func from(string: String) -> WeatherType? {
    return W.typeMap[string]
  }
}

这是一个小测试:

let str = "301"
let type = WeatherType.from(string: "owm\(str)")
print(type == .owm301)

Swift当前没有枚举实例的可枚举序列。 您拥有的一种选择是复制图标名称列表 ,然后搜索图标的名称,并将该索引用作枚举的rawValue:

let weatherIcons = [...]
let iconName = "owm300"
let possibleIconIndex = weatherIcons.index {
    $0.caseInsensitiveCompare(iconName) == .orderedSame
}
if let iconIndex = possibleIconIndex {
    let weatherIcon = WeatherIcon(rawValue: iconIndex)!
    // ...
} else {
    // graceful fallback for when the weather icon is missing
}

当然,您需要弄清楚从服务获取的数据和枚举名称之间的映射关系,但这可能很简单,例如"owm\\(weatherCode)"

当Swift 4.2登陆时,您将能够使您的枚举符合一个名为CaseIterable的新协议。 符合它的枚举将获得allCases静态变量的综合实现。 然后,您将可以使用该枚举自动构建字符串到枚举的字典:

let nameToEnum = WeatherIcon.allCases.map { (String($0), $0) }
let mapping = Dictionary(uniqueKeysWithValues: nameToEnum)

但是,这将要求WeatherIcon 声明CaseEnumerable一致性,因为添加extension不会起作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM