【问题标题】:Swift - Decode array of an arrays JSON dataSwift - 解码数组 JSON 数据的数组
【发布时间】:2020-03-15 20:04:40
【问题描述】:

我正在使用 Swift 5,并且正在尝试创建一个结构来保存 Google Sheets API 调用的内容。 我被“值”键困住了,我想获取哪些值,更改为 Int 类型并存储在我最近可以使用的单独数组变量中。

这是 API 的一个结果:

{
 "range": "Sheet1!A2:B4",
 "majorDimension": "ROWS",
 "values": [
   [
     "-10",
     "12"
   ],
   [
     "-9",
     "-15"
   ],
   [
     "-8",
     "-9"
   ]
   [
     "-7",
     "4"
   ]
 ]
}

在我之前的方法中,我遇到了一个错误:“应解码字符串,但找到了一个数组。”

所以我的问题是“价值观”的内部结构应该如何完成任务?

struct Sheet: Decodable {
    let range: String?
    let majorDimension: String?
    let values: [Values]?  
}

do {
   let json = try JSONDecoder().decode(Sheet.self, from: data)

  } catch let error {
      print(error as Any)
  }

谢谢!

【问题讨论】:

  • 你有一个错误 - “-9”后缺少逗号],你也可以尝试像app.quicktype.io这样的服务来验证和解析任何语言的JSON

标签: json swift jsondecoder


【解决方案1】:

请注意,您的 JSON 在此数组后缺少逗号:

[
 "-8",
 "-9"
]

假设您已修复该问题,您需要将类型设为 values [[String]]?

struct Response: Codable {
    // you don't actually need optional properties if you are sure they exist
    let range: String?
    let majorDimension: String?
    let values: [[String]]?

    // you don't need CodingKeys here since all your property names match the JSON keys
}

如果您希望数字为Doubles,您可以这样做(假设始终有效的数字):

struct Response: Codable {
    let range: String?
    let majorDimension: String?
    let values: [[Double]]?

    // now you need CodingKeys, but you don't need to give them raw values
    enum CodingKeys: String, CodingKey {
        case range
        case majorDimension
        case values
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        range = try container.decodeIfPresent(String.self, forKey: .range)
        majorDimension = try container.decodeIfPresent(String.self, forKey: .majorDimension)
        // use map to transform the strings to doubles
        values = try container.decodeIfPresent([[String]].self, forKey: .values)?
            .map { $0.map { Double($0)! } }
            // or if you want to filter out the invalid numbers...
            // .map { $0.compactMap(Double.init) }
    }
}

【讨论】:

  • 你可以使用compactMap而不是最后一张地图来避免强制展开
  • @JoakimDanielson 好主意。作为另一个选项添加。
  • @JoakimDanielson 实际上,这有意义吗?这是一个电子表格,所以不要期望二维数组有长度不等的数组。
  • 啊,也许不是。我并没有真正注意到这是来自电子表格的数据。
  • @SimbaNew 你写let values: [[Double]]?了吗,记得上一行末尾的?
【解决方案2】:

您发布的 JSON 无效(缺少逗号),但是当您修复它时,它可以在使用时解析

struct Sheet: Decodable {
    let range, majorDimension: String
    let values: [[String]]
}

即通过使values 成为二维字符串数组。

要将值转换为所需的Int 值,您可以提供一个访问器:

extension Sheet {
   var intValues: [[Int]] {
     return values.map {
       $0.compactMap { Int($0) }
     }
   }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多