Swift - декодирует массив массивов JSON данных - PullRequest
2 голосов
/ 15 марта 2020

Я использую Swift 5 и пытаюсь создать структуру для хранения содержимого вызова API Google Sheets. Я застрял с ключом «значения», значения которого я хочу получить, изменить на тип 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)
  }

Спасибо!

Ответы [ 2 ]

1 голос
/ 15 марта 2020

Обратите внимание, что в вашем 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
}

Если вы хотите, чтобы числа были Double с, вы можете сделать это (при условии всегда действительных чисел):

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) }
    }
}
1 голос
/ 15 марта 2020

Отправленный вами 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) }
     }
   }
}
...