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)的情况下访问枚举的这个元素?
Swift 目前没有枚举案例的可枚举序列。您的一个选择是复制 list of icon names,然后搜索您的图标名称,并将该索引用作枚举的原始值:
let weatherIcons = [...]
let iconName = "owm300"
let possibleIconIndex = weatherIcons.index {
[=10=].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
静态变量的合成实现。然后,您将能够使用该枚举自动构建 string-to-enum 字典:
let nameToEnum = WeatherIcon.allCases.map { (String([=11=]), [=11=]) }
let mapping = Dictionary(uniqueKeysWithValues: nameToEnum)
然而,这将要求 WeatherIcon
声明 符合 CaseEnumerable
,因为添加 extension
没有效果。
我能想到的最简单的方法之一是创建某种映射字典,您可以在其中跟踪天气响应代码和它映射到的 WeatherType,
let weatherCodeMapping: [Int: WeatherType] = [300: .owm300,
301: .owm301,
302: .owm302]
有了这个,你不需要知道任何具体的 rawValue,你可以简单地获取代码,
let weatherType = weatherCodeMapping[weatherCode]
然后根据 weatherType 为您的图像创建一些其他映射。
let weatherIcon = weatherIconMapping[weatherType]
或者直接创建一个从天气代码到图标的映射。
计划如下:
- 我们需要枚举所有枚举案例。我们将通过迭代原始值来做到这一点(幸运的是,
WeatherType
得到了 Int
的支持)。
- 我们将存储映射
String
到 WeatherType
的惰性初始化字典。
- 最后,我们声明一个静态函数,该函数 returns 是可选的
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)
几个小时以来,我一直在努力获取枚举的可变元素。
“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)的情况下访问枚举的这个元素?
Swift 目前没有枚举案例的可枚举序列。您的一个选择是复制 list of icon names,然后搜索您的图标名称,并将该索引用作枚举的原始值:
let weatherIcons = [...]
let iconName = "owm300"
let possibleIconIndex = weatherIcons.index {
[=10=].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
静态变量的合成实现。然后,您将能够使用该枚举自动构建 string-to-enum 字典:
let nameToEnum = WeatherIcon.allCases.map { (String([=11=]), [=11=]) }
let mapping = Dictionary(uniqueKeysWithValues: nameToEnum)
然而,这将要求 WeatherIcon
声明 符合 CaseEnumerable
,因为添加 extension
没有效果。
我能想到的最简单的方法之一是创建某种映射字典,您可以在其中跟踪天气响应代码和它映射到的 WeatherType,
let weatherCodeMapping: [Int: WeatherType] = [300: .owm300,
301: .owm301,
302: .owm302]
有了这个,你不需要知道任何具体的 rawValue,你可以简单地获取代码,
let weatherType = weatherCodeMapping[weatherCode]
然后根据 weatherType 为您的图像创建一些其他映射。
let weatherIcon = weatherIconMapping[weatherType]
或者直接创建一个从天气代码到图标的映射。
计划如下:
- 我们需要枚举所有枚举案例。我们将通过迭代原始值来做到这一点(幸运的是,
WeatherType
得到了Int
的支持)。 - 我们将存储映射
String
到WeatherType
的惰性初始化字典。 - 最后,我们声明一个静态函数,该函数 returns 是可选的
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)