我尝试从API解析JSON数据。一些键返回多种类型,或者有时不存在。只要键(值)在这里,一切都可以正常工作。但是,即使我在结构中将其声明为可选的,如果缺少该键,也会引发错误。从枚举MyValue中的init块引发该错误。

我的代码如下所示:

struct ServiceUnit: 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)
    case double(Double)
    case int(Int)
    case bool(Bool)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
            if let string = try? container.decode(String.self)  {
                self = .string(string)
                return
            }
            if let innerItem = try? container.decode(InnerItem.self) {
                self = .innerItem(innerItem)
                return
            }
            if let double = try? container.decode(Double.self) {
                self = .double(double)
                return
            }
            if let int = try? container.decode(Int.self) {
                self = .int(int)
                return
            }
            if let bool = try? container.decode(Bool.self){
                self = .bool(bool)
            }
            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)
        case .double(let x):
            try container.encode(x)
        case .int(let x):
            try container.encode(x)
        case .bool(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"
    }
}

JSON看起来像这样:
{
    "Description": null,
    "Group": "Beskrivning av enheten",
    "GroupDescription": null,
    "Id": "Description",
    "Name": "Mer om enheten",
    "Value": "Förskolans inriktningen omfattar barns flerspråkighet och integration. Förskolan ligger i Järva med närhet till parker, skog och natur och vi tillbringar mycket tid där. Vi ger barnen möjligheter till upplevelser och inlärning där deras nyfikenhet och upptäckarlust får styra. Förskolan använder sig av ett språkutvecklande och utforskande arbetssätt under hela förskoledagen. Vi arbetar med pedagogisk dokumentation, vi observerar och reflekterar kring arbetssättet för att utveckla verksamheten framåt. Vi dokumenterar vad barnen gör, så att det blir synligt vad och hur barnen lär sig. \r\nPedagogerna skapar förutsättningar för barnens utveckling genom att, i en tillåtande miljö, ge dem möjligheter att få arbeta med material som inbjuder till rolig och utforskande lek. Förskolan har ett eget tillagningskök som erbjuder näringsrik och spännande mat."
},
{
    "Description": null,
    "Group": "Relaterade dokument",
    "GroupDescription": null,
    "Id": "Documents",
    "Name": "Filer",
    "Value": [
        {
            "__type": "FileInfo",
            "Id": "040e5147-35a4-488e-8356-f47dad1fdc68",
            "Name": "Forskolan_Umma___Hyppingeplan_-_Foraldrar_Forskola.pdf"
        },
        {
            "__type": "FileInfo",
            "Id": "41202e0d-b642-40d0-b2c4-5af871c5a028",
            "Name": "Spånga-Tensta_033527 Umma Förskola, Hyppingeplan 2017.pdf"
        }
    ]
}

我试图在枚举MyValue的init中这样做:
 if container.decodeNil() == false {
   ...
 }else{
   self = .string("")
   return
 }

我也在struct init中尝试过此方法,但它也不起作用:
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        value = try! container.decodeIfPresent(MyValue.self, forKey: .value)
        description = try container.decode(String.self, forKey: .description)
        id = try container.decode(String.self, forKey: .id)
        group = try container.decode(String.self, forKey: .group)
        groupDescription = try container.decode(String.self, forKey: .groupDescription)
        name = try container.decode(String.self, forKey: .name)
    }

错误是:

错误类型不匹配(stockholmsParks.detailViewController.MyValue,Swift.DecodingError.Context(codingPath:[_JSONKey(stringValue:“Index 25”,intValue:25),CodingKeys(stringValue:“Value”,intValue:nil)]],debugDescription:“错误类型为MyValue”,underlyingError:nil))

在这种情况下,有人知道如何处理丢失的密钥吗?

最佳答案

问题是您为Value键分配了一个不是StringBoolIntDoubleInnerItem的值,因此返回值不会被击中并且控制权到达

 throw DecodingError.typeMismatch(MyValue.self,
  DecodingError.Context(codingPath: decoder.codingPath,
    debugDescription: "Wrong type for MyValue"))

注意: debugDescription中的MyValue类型错误

它打印出您在控制台中看到的错误,顺便说一句,使其成为可选,只有在看起来像

“值”:空

或键/值完全不存在

关于ios - 可编码结构-解析JSON时缺少键时的枚举,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52748348/

10-16 14:24