Swift Codable нескольких типов - PullRequest
       8

Swift Codable нескольких типов

0 голосов
/ 06 октября 2018

Я пытаюсь проанализировать API, возвращающий объект json.Моя проблема в том, что некоторые ключи иногда являются строкой, иногда объектом, подобным ключу «Значение» в следующем примере:

[
{
    "Description": null,
    "Group": "Beskrivning av enheten",
    "GroupDescription": null,
    "Id": "Description",
    "Name": "Mer om enheten",
    "Value": "Det finns möjlighet till parkering på gatorna runt om, men det är kantstenar och ganska branta backar för att komma upp till lekplatsen.\r\n\r\nUtanför själva lekplatsen finns en gungställning med en plan omväg in. Alla lekredskap står i sandytor, det finns många kanter. Runt hela lekplatsen går ett staket med öppningar i olika riktningar."
},
{
    "Description": null,
    "Group": "Bilder och film",
    "GroupDescription": null,
    "Id": "Image",
    "Name": "Huvudbild",
    "Value": {
        "__type": "FileInfo",
        "Id": "8871b3b1-14f4-4054-8728-636d9da21ace",
        "Name": "ullerudsbacken.jpg"
    }
}
]

Моя структура выглядит следующим образом:

struct ServiceUnit: Codable {
        let description: String?
        let group: String?
        let groupDescription: String?
        let id: String
        let name: String
        var value: String?
        struct ServiceUnitTypeInfo: Codable {
            let id: String
            let singularName: String?
            enum CodingKeys: String, CodingKey {
                case id = "Id"
                case singularName = "SingularName"
            }
        }
        let serviceUnitTypeInfo: ServiceUnitTypeInfo?
        let values: [String]?
        enum CodingKeys: String, CodingKey {
            case description = "Description"
            case group = "Group"
            case groupDescription = "GroupDescription"
            case id = "Id"
            case name = "Name"
            case value = "Value"
            case serviceUnitTypeInfo = "ServiceUnitTypeInfo"
            case values = "Values"
            case image = "Image"
        }
    }

IЯ должен сказать, что я полностью потерян (да, я новичок в быстрой работе), и я не могу найти решение своей проблемы.Я понимаю, что мне нужно использовать пользовательский init, но я не знаю как.

Ответы [ 2 ]

0 голосов
/ 04 апреля 2019

Опираясь на ответ @Sh_Khan и ответить на вопрос @Nikhi в комментариях (как вы можете получить доступ к значениям), я хотел бы добавить это к объявлению enum:

var innerItemValue: InnerItem? {
    switch self {
    case .innerItem(let ii):
        return ii
    default:
        return nil
    }
}

var stringValue: String? {
    switch self {
    case .string(let s):
        return s
    default:
        return nil
    }
}
0 голосов
/ 06 октября 2018

Можно попробовать

struct Root: Codable {
    let description,id: String
    let group,groupDescription: String?
    let name: String
    let value: MyValue

    enum CodingKeys: String, CodingKey {
        case description = "Description"
        case group = "Group"
        case groupDescription = "GroupDescription"
        case id = "Id"
        case name = "Name"
        case value = "Value"
    }
}

enum MyValue: Codable {
    case string(String)
    case innerItem(InnerItem)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(InnerItem.self) {
            self = .innerItem(x)
            return
        }
        throw DecodingError.typeMismatch(MyValue.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for MyValue"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let x):
            try container.encode(x)
        case .innerItem(let x):
            try container.encode(x)
        }
    }
}

struct InnerItem: Codable {
    let type, id, name: String

    enum CodingKeys: String, CodingKey {
        case type = "__type"
        case id = "Id"
        case name = "Name"
    }
}

do {
  let result = try JSONDecoder().decode([Root].self,from:data)
  print(result)
}
catch {
  print(error)
}
...