【问题标题】:Decoding an array of objects with nested heterogeneous child objects解码具有嵌套异构子对象的对象数组
【发布时间】:2021-07-16 21:30:42
【问题描述】:

下面是来自服务器的响应示例。

该列表由在info 字段中具有异构子结构的元素组成。它们每个都包含 3 个具有相同类型的字段,但它们具有不同的键。

我不知道如何解码,到目前为止我还没有遇到过这样的问题。我在 Internet 上找不到适合这种情况的示例。

一开始想解码枚举type,并根据它选择合适的info结构,但是不行。

非常感谢您的帮助。

{
  "data":[
    {
      "type":"league",
      "info":{
        "name":"NBA",
        "sport":"Basketball",
        "website":"https://nba.com/"
      }
    },
    {
      "type":"player",
      "info":{
        "name":"Kawhi Leonard",
        "position":"Small Forward",
        "picture":"https://i.ibb.co/b5sGk6L/40a233a203be2a30e6d50501a73d3a0a8ccc131fv2-128.jpg"
      }
    },
    {
      "type":"team",
      "info":{
        "name":"Los Angeles Clippers",
        "state":"California",
        "logo":"https://logos-download.com/wp-content/uploads/2016/04/LA_Clippers_logo_logotype_emblem.png"
      }
    }
  ]
}

【问题讨论】:

  • 我推荐一个具有关联类型的枚举,如描述的here
  • 你能知道什么是所有可能的键吗?如果是,那么您可以将它们全部声明为可选项。
  • @AhmadF 我知道所有类型,但是将所有字段声明为可选项不是一种选择 - 代码库会增长太快。
  • @vadian,我听从了你的建议,创建了以下代码 sn-p:pastebin.com/S3uSXgtU 2 个枚举不是一团糟吗?

标签: arrays json swift decodable


【解决方案1】:

你在pastebin上的代码太复杂了,我是说这个

let jsonString = """
{
  "data":[
    {
      "type":"league",
      "info":{
        "name":"NBA",
        "sport":"Basketball",
        "website":"https://nba.com/"
      }
    },
    {
      "type":"player",
      "info":{
        "name":"Kawhi Leonard",
        "position":"Small Forward",
        "picture":"https://i.ibb.co/b5sGk6L/40a233a203be2a30e6d50501a73d3a0a8ccc131fv2-128.jpg"
      }
    },
    {
      "type":"team",
      "info":{
        "name":"Los Angeles Clippers",
        "state":"California",
        "logo":"https://logos-download.com/wp-content/uploads/2016/04/LA_Clippers_logo_logotype_emblem.png"
      }
    }
  ]
}
"""

struct Response: Decodable {
    let data: [Datum]
}

struct League: Codable {
    let name: String
    let sport: String
    let website: URL
}

struct Player: Codable {
    let name: String
    let position: String
    let picture: URL
}

struct Team: Codable {
    let name: String
    let state: String
    let logo: URL
}

enum Datum: Decodable {
    case league(League)
    case player(Player)
    case team(Team)
    
    enum DatumType: String, Decodable {
        case league
        case player
        case team
    }
    
    private enum CodingKeys : String, CodingKey { case type, info }
 
    init(from decoder : Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let type = try container.decode(DatumType.self, forKey: .type)
        switch type {
        case .league:
            let item = try container.decode(League.self, forKey: .info)
            self = .league(item)
        case .player:
            let item = try container.decode(Player.self, forKey: .info)
            self = .player(item)
        case .team:
            let item = try container.decode(Team.self, forKey: .info)
            self = .team(item)
        }
    }
}

do {
    let response = try JSONDecoder().decode(Response.self, from: Data(jsonString.utf8))
    let data = response.data
    print(data)
//    receivedData.forEach { (datum) in
//        let cell = Cell()
//        cell.configure(with: datum.info.rowData)
//        cells.append(cell)
//    }
//    cells.forEach({ print($0.title, $0.subtitle) })
} catch {
    print(error)
}

在单元格中切换类型

switch datum {
    case .league(let league): // so something with league
    case .player(let player): // so something with player
    case .team(let team): // so something with team
} 

【讨论】:

  • 谢谢你,@vadian!您能否告诉我如何将这些 datum 嵌套值放入以下结构 sn-p 中? pastebin.com/Lc1u3aQ2我想有一个Items的列表,其中Item<Displayable>,但恐怕这是不可能的,因为只有struct/enum/class类型可以符合协议。
  • 答案取决于使用结构的上下文。请提出新问题并提供更多信息。请直接将相关代码作为文本而不是外部链接添加到问题中。
猜你喜欢
  • 2022-01-08
  • 2020-09-03
  • 2017-01-08
  • 1970-01-01
  • 2022-11-20
  • 2021-10-04
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
相关资源
最近更新 更多