7

値の配列を持つ JSON があります。

[
    { "tag": "Foo", … },
    { "tag": "Bar", … },
    { "tag": "Baz", … },
]

structこの配列を、特定の型がタグに依存する s の配列にデコードしたい:

protocol SomeCommonType {}

struct Foo: Decodable, SomeCommonType { … }
struct Bar: Decodable, SomeCommonType { … }
struct Baz: Decodable, SomeCommonType { … }

let values = try JSONDecoder().decode([SomeCommonType].self, from: …)

それ、どうやったら出来るの?現時点では、この少し醜いラッパーがあります:

struct DecodingWrapper: Decodable {

    let value: SomeCommonType

    public init(from decoder: Decoder) throws {
        let c = try decoder.singleValueContainer()
        if let decoded = try? c.decode(Foo.self) {
            value = decoded
        } else if let decoded = try? c.decode(Bar.self) {
            value = decoded
        } else if let decoded = try? c.decode(Baz.self) {
            value = decoded
        } else {
            throw …
        }
    }
}

その後:

let wrapped = try JSONDecoder().decode([DecodingWrapper].self, from: …)
let values = wrapped.map { $0.value }

より良い方法はありますか?

4

3 に答える 3

1

マッピングに Dictionary を使用することもできます。

protocol SomeCommonType {}

struct Foo: Decodable, SomeCommonType { }
struct Bar: Decodable, SomeCommonType { }
struct Baz: Decodable, SomeCommonType { }

let j: [[String:String]] = [
    ["tag": "Foo"],
    ["tag": "Bar"],
    ["tag": "Baz"],
    ["tag": "Undefined type"],
    ["missing": "tag"]
]

let mapping: [String: SomeCommonType.Type] = [
    "Foo": Foo.self,
    "Bar": Bar.self,
    "Baz": Baz.self
]

print(j.map { $0["tag"].flatMap { mapping[$0] } })
// [Optional(Foo), Optional(Bar), Optional(Baz), nil, nil]

print(j.flatMap { $0["tag"].flatMap { mapping[$0] } })
// [Foo, Bar, Baz]
于 2017-11-08T14:56:18.757 に答える