json - 使用 Swift Decodable 进行动态(但称为另一个键值)JSON 解码

标签 json swift

我查看了类似问题的答案,我无法很好地理解codingKey,此外它并不完全适用于我的情况,因为该键并不完全“未知”,它是前一个键的值。 我的API:

{
  "api": {
    "results": 1,
    "fixtures": [
      {
        "homeTeam": {
          "team_name": "Tottenham"
        },
        "awayTeam": {
          "team_name": "Everton"
        },
        "lineups": {
          "Tottenham": {
            "formation": "4-2-3-1"
          },
          "Everton": {
            "formation": "4-2-3-1"
          }
        }
      }
    ]
  }
}

我的代码:

class matchApiObject: Decodable
{
    let fixtures: [fixture]
    init (fixtures: [fixture])
    {
        self.fixtures = fixtures
    }
}

class fixture: Decodable
{
    let homeTeam: matchHomeTeamObject?
    let lineups: lineUpsObject?
    init (homeTeam: matchHomeTeamObject?, lineups: lineUpsObject?)
    {
        self.homeTeam = homeTeam
        self.lineups = lineups
    }
}

class matchHomeTeamObject: Decodable
{
    let team_name: String?
    init (team_name: String?)
    {
        self.team_name = team_name
    }
}

class lineUpsObject: Decodable
{
    struct homeLineUp: Decodable
    {
        let formation: String?
        init(formation: String?)
        {
            self.formation = formation
        }
    }
    struct awayLineUp: Decodable
    {
        let formation: String?
        init (formation: String?)
        {
            self.formation = formation
        }
    }
}

显然,阵容对象的键不会是“homeLineUp”,但根据 api 示例,它是 homeTeam.team_name 的值。

所以我想象的解决方案是:

class lineUpsObject: Decodable
{
    struct homeTeam.team_name: Decodable
    {
        let formation: String?
        init(formation: String?)
        {
            self.formation = formation
        }
    }
    struct awayTeam.team_name: Decodable
    {
        let formation: String?
        init (formation: String?)
        {
            self.formation = formation
        }
    }
}

这是不可能的,我知道我必须为此使用编码键,但我不明白如何将键的名称声明为前一个键值的值我不明白什么是 stringValue: String或 intValue: Int do 在codingkey答案中做或它们如何应用在这里,谢谢。

最佳答案

一个简单的解决方案是将lineups解码为字典,我以大写字母开头的所有结构体命名以符合命名约定。

不需要 init 方法

struct Root : Decodable {
    let api : API
}

struct API : Decodable {
    let results : Int
    let fixtures : [Fixture]
}

struct Fixture : Decodable {
    let homeTeam, awayTeam: Team
    let lineups : [String:Lineup]
}

struct Team  : Decodable {
    let teamName : String
}

struct Lineup : Decodable {
    let formation : String
}

要将snake_cased键转换为camelCased结构成员,请添加适当的策略

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

更复杂的解决方案是将formation数据放入Team结构中,但这需要实现init(fromdecoder:) Fixture 中的方法。

关于json - 使用 Swift Decodable 进行动态(但称为另一个键值)JSON 解码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57529012/

相关文章:

c++ - swift 3 中是否有等效的 c++ shared_ptr?

ios - reloadRows 将创建新单元格

arrays - 如何创建一个给出素数+ bool 值的函数?

java - 将 java.util.ArrayList 转换为 gson.JsonElement

javascript - 如何从javascript json接收WebAPI中的字典

java - 如何将 "break"JSON 树分解成单独的列表,从父级开始一直到 Java 中连接的每个子级?

ios - 如何使用for循环从具有多个变量的数据库中获取值?

json - 用于中间/临时存储的 Azure cosmos db 与 blob 存储

json - Flutter 错误 : Expected a value of type 'FutureOr<List<dynamic>>' , 但得到了 '_JsonMap' 类型之一

swift - Clean swift 如何将数据传回 viewController