【问题标题】:Decoding multiple types for the same key [duplicate]为同一个键解码多种类型[重复]
【发布时间】:2022-01-25 15:42:37
【问题描述】:

我的 Json 结构如下:

"config": {
    "ids": false,
    "names": [
      {
        "name": "value1"
      },
      {
        "name": "value2"
      }
    ]
  }

我遇到的问题是响应也可以具有以下格式:

"config": {
    "ids": [
      {
        "id": "id1"
      },
      {
        "id": "id2"
      }
    ],
    "names": false
  }

关于如何实现这一点的任何建议?

当前状态:

struct Config: Decodable, Equatable {
    let names: Names?
}

struct Names: Decodable, Equatable {
    let names: [[String: String]]?
    
    init(from decoder: Decoder) throws {
        facets = try container.decode([[String: String]].self, forKey: ???)
    }
}

【问题讨论】:

  • 对每种配置类型使用不同的结构。在将 json 序列化为结构之前,请执行某种检查以查看 json 具有哪些配置。

标签: swift


【解决方案1】:

对象结构

尝试执行以下操作:

// MARK: - Config
struct Config: Codable {
    let ids: IDS
    let names: Names
}

enum IDS: Codable {
    case bool(Bool)
    case idArray([ID])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Bool.self) {
            self = .bool(x)
            return
        }
        if let x = try? container.decode([ID].self) {
            self = .idArray(x)
            return
        }
        throw DecodingError.typeMismatch(IDS.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for IDS"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .bool(let x):
            try container.encode(x)
        case .idArray(let x):
            try container.encode(x)
        }
    }
}

// MARK: - ID
struct ID: Codable {
    let id: String
}

enum Names: Codable {
    case bool(Bool)
    case nameArray([Name])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Bool.self) {
            self = .bool(x)
            return
        }
        if let x = try? container.decode([Name].self) {
            self = .nameArray(x)
            return
        }
        throw DecodingError.typeMismatch(Names.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Names"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .bool(let x):
            try container.encode(x)
        case .nameArray(let x):
            try container.encode(x)
        }
    }
}

// MARK: - Name
struct Name: Codable {
    let name: String
}

我是怎么做到的

我使用QuickType 生成了它,它可以将 JSON 转换为 Swift 对象。为了实现上述目的,我将 JSON 作为Config 选项列表输入,然后从给定输出中删除我不需要的部分...

[
    {
        "config": {
        "ids": false,
        "names": [
          {
            "name": "value1"
          },
          {
            "name": "value2"
          }
        ]
      }
    },
    {
      "config": {
        "ids": [
          {
            "id": "id1"
          },
          {
            "id": "id2"
          }
        ],
        "names": false
      }
    }
]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 2019-12-08
    • 2020-12-21
    • 2020-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多