我有一个从API获得的JSON响应,JSON如下所示

{
    "data": [
        {
            "_id": "63d9d2d57c0cfe791b2b19f6",
            "step": {
                "_id": "step1",
                "status": "STARTED",
                "children": [
                    {
                        "_id": "step2",
                        "status": "NOT_STARTED",
                        "children": [
                            {
                                "_id": "step3",
                                "status": "NOT_STARTED",
                                "children": [
                                    {
                                        "_id": "step3",
                                        "status": "NOT_STARTED"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            },
            "status": "IN_PROGRESS",
            "createdBy": "2700930039"
        }
    ]
}

JSON可以在彼此内部具有多层子对象.我需要将此JSON响应映射到SWIFT中的模型

以下是我为Json创建的模型

struct NestedJsonModel:Decodable {
   var data:[LotData]
}

struct LotData:Decodable {
   var _id: String
   var step: StepDetails
   var status: String
   var createdBy: String
}

struct StepDetails:Decodable {
   var _id: String
   var status: String
   var children: [ChildSteps]
}

struct ChildSteps:Decodable {
   var _id: String
   var status: String
   var children: [StepDetails] //because children contains the same model as Step Details
}

以下是译码代码

let jsonData = data.data(using: .utf8)!
do {
    let decoder = JSONDecoder()
    let tableData = try decoder.decode(NestedJsonModel.self, from: jsonData)
    result = tableData.data
    print("****************")
    print(result!)
    print("****************")
}
catch {
    print (error)
}

但我一直收到这样的错误

keyNotFound(CodingKeys(stringValue: "children", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "step", intValue: nil), CodingKeys(stringValue: "children", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "children", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"children\", intValue: nil) (\"children\").", underlyingError: nil))

推荐答案

请注意,JSON的最内层没有"子"键,但是ChildSteps struct 确实有一个非可选的children属性,需要为其赋值.

要解决这个问题,您只需将children设置为可选类型.

还请注意,由于StepDetailsChildSteps具有相同的属性,因此您也可以将它们合并.

struct NestedJsonModel:Decodable {
   var data:[LotData]
}

struct LotData:Decodable {
   var _id: String
   var step: StepDetails
   var status: String
   var createdBy: String
}

struct StepDetails:Decodable {
   var _id: String
   var status: String
   var children: [StepDetails]?
}

如果您不需要区分"有一个空的children数组"和"没有children个键",那么您可以使children属性成为非可选的,并在找不到键时用一个空数组来初始化它.

无需手写您自己的自定义解码逻辑即可方便地完成此操作,方法是使用属性包装,如this answer中所示:

@propertyWrapper
struct DefaultEmptyArray<T:Decodable>: Decodable {
    var wrappedValue: [T] = []
    
    init() {}
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        wrappedValue = try container.decode([T].self)
    }
}

extension KeyedDecodingContainer {
    func decode<T:Decodable>(_ type: DefaultEmptyArray<T>.Type,
                forKey key: Key) throws -> DefaultEmptyArray<T> {
        try decodeIfPresent(type, forKey: key) ?? .init()
    }
}

// in StepDetails
@DefaultEmptyArray var children: [StepDetails]?

Swift相关问答推荐

SwiftUI状态更新

如何在visionOS上删除PhotosPicker背景 colored颜色 ?

SwiftUI轨迹绘制怪异

SwiftUI - NavigationLink(value:)和navigationDestination不工作

如何获取嵌套数组中项的路径以修改数组?

从Swift中的泛型类继承?

在一行语句中比较Date.now的相等性是否安全

Swift通过设置变量B自动设置变量A的值

允许视图在视图内更改

如何使用Swift宏和@Observable和@Environment?

为什么自定义串行队列的目标是全局队列时,Swift中不会并发执行?

从一个范围减go 多个范围

使用 swift 的 Firebase 身份验证

与 SwiftUI 中的 onChange 修饰符相比,objectWillChangeSequence 的目的是什么?

如何在 RxSwift 中获取 controlEvent 类型?

Vapor - 流利的,将对象保存到 PostgreSQL

快速的 AES 加密

如何在 Swift 中复制字典?

是 swift 中另一个日期的同一周、月、年的日期

如何快速将弹出框调整为表格视图中内容的大小?