【发布时间】:2018-05-29 13:58:12
【问题描述】:
在我的项目中,我有几个在任何地方都使用的枚举,这些枚举是基于外部 json 创建的,因此输入始终是可选的。如果无法从输入创建枚举,我将定义一个默认值。
我现在做事的例子:
enum TextAlign:String {
case left, center, right
}
let rawData = [String:Any]()
func getTextAlign() -> TextAlign {
if let rawTextAlignString = rawData["textAlign"] as? String, let align = TextAlign(rawValue: rawTextAlignString) {
return align
}
return TextAlign.left
}
let textAlign = self.getTextAlign()
这显然有效,但我想让我的构造函数更快速、更通用并适用于更多这些枚举。我的目标是像这样实例化这些枚举:
let textAlign = TextAlign(rawOptionalValue: rawData["textAlign"] as? String) ?? TextAlign.left
所以我基本上想要一个可失败的初始化程序,我可以为 TextAlign 枚举编写它,但必须有一种方法以更“通用”的方式声明它,以便我可以在我的所有枚举上使用初始化程序:String 实例。 我在 swift 中对泛型的语法和选项有些挣扎。
有什么想法吗?
更新 #1
我看到很多答案都没有错,但可能我在寻找的内容上不够清楚。
我有更多这样的枚举:
enum TextAlign:String {
case left, center, right
}
enum CornerRadius:String {
case none, medium, large
}
enum Spacing:String {
case tight, medium, loose
}
我只想定义 1 个可以初始化所有这些枚举的函数。 (不是因为我懒,而是因为我想了解如何为此使用泛型)
我可能需要的是扩展中的一些静态函数,适用于所有这些“String/RawRepresentable”枚举。我不想为每个枚举编写所有这些失败的初始化程序。 (我相信应该可以,但我不知道语法)
更新 #2
在玩了一下 Joakim 的回答后,我想出了以下解决方案:
extension RawRepresentable {
static func create<T:Any>(_ value: Any?, defaultValue: Self) -> Self where Self.RawValue == T {
guard let rawValue = value as? T, let instance = Self.init(rawValue: rawValue) else {
return defaultValue
}
return instance
}
}
这使我可以使用此函数实例化 String 和 Int(以及更多)类型的枚举。像这样:
enum TextAlign:String {
case left, center, right
}
enum CornerRadius:Int {
case none, medium, large
}
let json:[String:Any] = [
"textAlign":"left",
"cornerRadius":0
]
let cornerRadius = CornerRadius.create(json["cornerRadius"], defaultValue: .medium)
let align = TextAlign.create(json["textAlign"], defaultValue: .center)
我喜欢我可以将 Any? 作为参数传递,并且它通过 let rawValue = value as? T 自行处理转换。
更新#3(解决方案)
好的,这一切的复杂性仍然让我有点困扰,所以我尝试了 init 路由,imo 看起来更干净。整个事情现在看起来像这样:
extension RawRepresentable {
init(from value: Any?, or defaultValue: Self) {
self = Self.init(from: value) ?? defaultValue
}
init?(from value: Any?) {
guard let rawValue = value as? Self.RawValue, let instance = Self.init(rawValue: rawValue) else {
return nil
}
self = instance
}
}
为了方便起见,我创建了一个带有默认值的可失败和不可失败的 init。
现在我可以像这样实例化任何枚举:
let cornerRadius = CornerRadius(json["cornerRadius"], or: .medium)
// or an optional one
let align = TextAlign(json["textAlign"])
现在我完成了更新...
【问题讨论】:
-
不清楚。您要求一种通用的方式,但是您的一些 cmets 建议您要像 TextAlign(...) 等那样进行初始化,但这不是通用的。
-
是的。我要求一种通用的方式,如果可能的话,我想这样初始化。如果不可能,那就不要:)
标签: swift generics enums optional