bla*_*acx 6 generics enums json ios swift
我有大约20个枚举的扩展名,如下所示:
extension CurrencyValue : JSONDecodable {
static func create(rawValue: String) -> CurrencyValue {
if let value = CurrencyValue(rawValue: rawValue) {
return value
}
return .unknown
}
static func decode(j: JSONValue) -> CurrencyValue? {
return CurrencyValue.create <^> j.value()
}
}
extension StatusValue : JSONDecodable {
static func create(rawValue: String) -> StatusValue {
if let value = StatusValue(rawValue: rawValue) {
return value
}
return .unknown
}
static func decode(j: JSONValue) -> StatusValue? {
return StatusValue.create <^> j.value()
}
}
Run Code Online (Sandbox Code Playgroud)
它们几乎是相同的,除了枚举类型名称,我有20个 - 这显然是非常愚蠢的.有没有人知道如何将它们减少到一个,也许是通过使用泛型?我现在不知道.
UPDATE
枚举就像这样简单:
enum CurrencyValue : String {
case EUR = "EUR"
case unknown = "unknown"
}
enum StatusValue : String {
case ok = "ok"
case pending = "pending"
case error = "error"
case unknown = "unknown"
}
Run Code Online (Sandbox Code Playgroud)
我们假设以下内容:
必须有一些技巧,不要多次实现相同的扩展,只需改变类型.
UPDATE
正如Gregory Higley在下面所说,我使用的是JSON lib Argo.你可以阅读那里的运营商.
您问题的本质是您希望在实现 Argo 时避免为所有这些枚举编写样板代码JSONDecodable。看起来您还添加了一个create方法,该方法不是 的类型签名的一部分JSONDecodable:
public protocol JSONDecodable {
typealias DecodedType = Self
class func decode(JSONValue) -> DecodedType?
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这无法做到。Swift 协议不是 mixins。除运算符外,它们不能包含任何代码。(我真的希望这个问题在 Swift 的未来更新中得到“修复”。协议的可重写默认实现将是令人惊奇的。)
当然,您可以通过多种方式简化您的实现:
.unknown并使用选项。(另外,你应该称之为.Unknown。Swift 枚举值的约定是以大写字母开头。证明?看看 Apple 所做的每个枚举。我找不到一个以小写字母开头的示例.)create现在只是 的功能别名init?,并且可以非常简单地实现。decode. 尽管他可能认为这是暗示的,但他没有建议的是使用它来实现JSONDecodable.decode。应提问者的要求,这里有一个来自游乐场的快速实现。我从来没有用过Argo。事实上,在我看到这个问题之前,我从来没有听说过它。我简单地通过应用我对 Swift 的了解来检查 Argo 的源代码并推理出来来回答这个问题。该代码是直接从游乐场复制的。它没有使用Argo,但使用了相关部分的合理复制品。归根结底,这个问题与Argo无关。这是关于 Swift 的类型系统的,下面代码中的所有内容都有效地回答了问题并证明它是可行的:
enum JSONValue {
case JSONString(String)
}
protocol JSONDecodable {
typealias DecodedType = Self
class func decode(JSONValue) -> DecodedType?
}
protocol RawStringInitializable {
init?(rawValue: String)
}
enum StatusValue: String, RawStringInitializable, JSONDecodable {
case Ok = "ok"
case Pending = "pending"
case Error = "error"
static func decode(j: JSONValue) -> StatusValue? {
return decodeJSON(j)
}
}
func decodeJSON<E: RawStringInitializable>(j: JSONValue) -> E? {
// You can replace this with some fancy Argo operators,
// but the effect is the same.
switch j {
case .JSONString(let string): return E(rawValue: string)
default: return nil
}
}
let j = JSONValue.JSONString("ok")
let statusValue = StatusValue.decode(j)
Run Code Online (Sandbox Code Playgroud)
这不是伪代码。它是直接从工作的 Xcode Playground 复制的。
如果您创建了协议RawStringInitializable并让所有枚举都实现了它,那么您将获得成功。由于您的枚举都具有关联的String原始值,因此它们无论如何都会隐式实现此接口。您只需做出声明即可。全局decodeJSON函数使用此协议以多态方式处理所有枚举。