Swift - 解码数组 JSON 数据的数组

Posted

技术标签:

【中文标题】Swift - 解码数组 JSON 数据的数组【英文标题】:Swift - Decode array of an arrays JSON data 【发布时间】: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 【参考方案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) 
     
   

【讨论】:

以上是关于Swift - 解码数组 JSON 数据的数组的主要内容,如果未能解决你的问题,请参考以下文章

Swift - JSON解码返回空数组

使用swift解码巨大的JSON数组URL

Swift Json 解码不确定传入数据

如何使用数组对 API 数据进行 Json 解码?

使用 swift Codable 从 JSON 数组中提取数据

无法在 Swift 中解析 JSON。 “应解码 Dictionary<String, Any>,但找到了一个数组。” [复制]