如何在Swift中解析嵌套JSON时传递值

pn9klfpd  于 2022-11-26  发布在  Swift
关注(0)|答案(1)|浏览(114)

我想将父区域ID传递给其子区域,同时根据所附响应解析嵌套JSON结构。在此,我想为每个子区域插入“parentId”,该子区域将链接到其直接父区域。

{
  "areas": [
    {
      "id": "271341877549072423",
      "name": "Breeze Office Tower",
      "children": [
        {
          "id": "271341877549072424",
          "name": "100 flinders street",
          "position": 0,
          "children": []
        },
        {
          "id": "271341877549130929",
          "name": "100 flinders street",
          "position": 1,
          "children": []
        },
        {
          "id": "271341877549072425",
          "name": "100 Flinder Stree",
          "position": 2,
          "children": [
            {
              "id": "271341877549072426",
              "name": "Büro",
              "position": 0,
              "children": [
                {
                  "id": "271341877549072427",
                  "name": "Dachgeschoß",
                  "position": 0,
                  "children": []
                }
              ]
            }
          ]
        },
        {
          "id": "271341877549130931",
          "name": "100 Flinder Stree",
          "position": 3,
          "children": [
            {
              "id": "271341877549130933",
              "name": "Büro",
              "position": 0,
              "children": [
                {
                  "id": "271341877549130935",
                  "name": "Dachgeschoß",
                  "position": 0,
                  "children": []
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

我的JSON可编码模型结构如下所示:

struct AreaModel: Decodable {
    var areas: [NestedAreaModel]?
}

struct NestedAreaModel: Codable {
    let areaId: String
    let areaName: String
    let children: [NestedAreaModel]
    let hasChildren: Bool
    var areaPosition: Int16?
    var parentId: String?
    var projectId: String?
    
    enum CodingKeys: String, CodingKey {
        case areaId = "id"
        case areaName = "name"
        case areaPosition = "position"
        case children
    }
    
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        self.areaId = try values.decode(String.self, forKey: .areaId)
        self.children = try values.decode([NestedAreaModel].self, forKey: .children)
        self.areaName = try values.decode(String.self, forKey: .areaName)
        self.projectId = ORAUserDefaults.selectedProjectId()
        self.areaPosition = try values.decodeIfPresent(Int16.self, forKey: .areaPosition)
        if !self.children.isEmpty {
            self.hasChildren = true
            self.parentId = self.areaId
        } else {
            self.hasChildren = false
        }
    }
}

这里我不能设置父Id,它总是指向自己的id。

qij5mzcb

qij5mzcb1#

正如我在注解中已经指出的,您需要迭代解码的子对象,并将它们各自的parentId设置为当前的areaId
一种可能的解决方案是:

init(from decoder: Decoder) throws {
    let values = try decoder.container(keyedBy: CodingKeys.self)
    self.areaId = try values.decode(String.self, forKey: .areaId)
    // decode the children to a local var
    var children = try values.decode([NestedAreaModel].self, forKey: .children)
    self.areaName = try values.decode(String.self, forKey: .areaName)
    self.projectId = ORAUserDefaults.selectedProjectId()
    self.areaPosition = try values.decodeIfPresent(Int16.self, forKey: .areaPosition)
    // if there are children loop over them and assign your id
    if !children.isEmpty {
        self.hasChildren = true
        for (index, _ ) in children.enumerated(){
            children[index].parentId = areaId
        }
    } else {
        self.hasChildren = false
    }
    // assign to self
    self.children = children
}

使用给定JSON进行测试:

let decoded = try JSONDecoder().decode(AreaModel.self, from: data)

print(decoded.areas?[0].areaId)
print(decoded.areas?[0].children[0].parentId)

结果:

Optional("271341877549072423")
Optional("271341877549072423")

备注:关于您对复杂性的意见:children[index].parentId = areaId对每个子节点只运行一次,而不管层深度如何,所以这个函数是(O)n。

相关问题