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

How to pass a value while parsing a nested JSON in Swift

提问人:Bappaditya 提问时间:11/23/2022 更新时间:11/23/2022 访问量:104

问:

我想将父区域 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 Codable 模型结构如下所示,

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。

iOS JSON Swift 解析 可编码

评论

0赞 burnsi 11/23/2022
self.parentId = self.areaId没有意义。难道你不应该遍历孩子并设置他们的 ?parentIdareaId
0赞 Bappaditya 11/23/2022
一个特定区域可以有多少个级别的子级是没有限制的,所以如果我们使用递归,不会创建一个N^(子区域级别的数量),最多可以有10个级别。所以想按 N 时间复杂度的顺序来做这件事

答:

0赞 burnsi 11/23/2022 #1

正如我在评论中指出的那样,您需要遍历解码的子项并将其各自设置为当前 .parentIdareaId

一种可能的解决方案是:

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")

言论: 关于你对复杂性的评论:无论级别如何,每个孩子只运行一次。所以这个函数是 (O)n。children[index].parentId = areaId