【问题标题】:Decoding an Array in a Swift model (Decodable)在 Swift 模型中解码数组(可解码)
【发布时间】:2019-05-23 05:39:25
【问题描述】:

我正在从 API 中检索 JSON,并且我想为我使用的每个端点创建一个模型。

所有端点都使用这种格式:

{
  "id": "xxxxxx",
  "result": {…},
  "error": null
}

关键是:

  • id 始终是一个字符串
  • error 可以是 null 也可以是包含键的对象
  • result 可以是 null;一个对象或一个数组。

我遇到的问题是,在其中一个端点上,结果是数组数组:

{
  "id": "xxxxxx",
  "result": [
      [
          "client_id",
          "name",
          50,
          "status"
      ]
  ],
  "error": null
}

如您所见,我有数组数组,其中的值可以是字符串或整数。

如何使用 Decodable 协议对其进行解码,然后根据它们的原始值将解码后的值用作 String 或 Int?

【问题讨论】:

  • "error" 可以是什么对象?
  • 向我们展示您正在使用的 Decodable 结构或类。如果您不显示代码,我们将无法修复您的代码。
  • 最简单的解决方案是使用两个独立的模型。不同的端点返回不同的数据模型是正常的。

标签: arrays swift decodable encodable


【解决方案1】:
import Foundation

let string =  """
{
    "id": "xxxxxx",
    "result": [
        [
            "client_id",
            "name",
            50,
            "status"
        ]
    ],
    "error": null
}
"""

struct Container: Codable {
    let id: String
    let result: [[Result]]
    let error: String?
}

enum Result: Codable {
    case integer(Int)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Int.self) {
            self = .integer(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Result.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Result"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self)
    }
}

let jsonData = string.data(using: .utf8)!
let container = try? JSONDecoder().decode(Container.self, from: jsonData)

print(container)

改进了@ArinDavoodian 的回答。

读取数据:

container?.result.first?.forEach { object in
    switch object {
    case let .integer(intValue):
        print(intValue)
        break
    case let .string(stringValue):
        print(stringValue)
        break
    }
}

一个简单的解决方案:

let yourInsideArray = container?.result.first!
for index in 0..<yourInsideArray.count {
let yourObjectInsideThisArray = yourInsideArray[i]
//do some
 switch yourObjectInsideThisArray {
    case let .integer(intValue):
        print(intValue)
        break
    case let .string(stringValue):
        print(stringValue)
        break
    }
}

【讨论】:

  • 为什么不简单地func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(self) }
  • 有趣的认为游乐场有效但显示(12716 次)而不是 4
  • 你也可以简化你的解码器init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() try self = (try? .integer(container.decode(Int.self))) ?? .string(container.decode(String.self)) }
  • 在我的操场上只有 4 次
  • 我可能需要一个新的 Playground 文件 kkk 来处理上面的许多代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-09
相关资源
最近更新 更多