#swift #codable
#swift #codable
Вопрос:
Итак, я столкнулся с довольно сложной проблемой для решения. Мой JSON-код имеет довольно странную структуру. Он имеет следующую структуру:
{
"title": [
[
"Temperature",
"9 u00b0C (283 u00b0F)",
"Good"
],
[
"Visibility",
"10 KM (6.2 Mi)",
"Good"
]
]
}
С помощью следующего кода я смог распечатать некоторый простой json-код:
import UIKit
struct WeatherItem: Decodable {
let title: String?
let value: String?
let condition: String?
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let jsonUrlString = "http://somelinkhere"
guard let url = URL(string: jsonUrlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, err) in
guard let data = data else { return }
do {
let weather = try JSONDecoder().decode(WeatherItem.self, from: data)
print(weather.title)
} catch let jsonErr{
print("error", jsonErr)
}
}.resume()
}
}
Но проблема в том, что мой вывод для всех 3 переменных, title, value и condition равен нулю.
Я уверен, что мне нужно изменить код структуры, но я не знаю каким образом.
Как мне перейти к JSON-коду без заголовка?
Комментарии:
1. Приведенный вами пример JSON кажется немного не таким. Я скопировал и вставил это в jsonformatter.curiousconcept.com и он говорит, что это недопустимо. Итак, если вы можете предоставить допустимый JSON, это помогло бы.
2. @LuisFRamirez json правильный, он просто отсутствует
{
и}
3. А, ладно. Думаю, не хватало скобок.
4. привет, спасибо за вашу помощь! Я попробовал ваше решение, но оно ничего не напечатало
5. полный json здесь: virtualflight.ddns.net/api/weather.php?icao=ehrd
Ответ №1:
Вам придется написать инициализатор декодирования самостоятельно:
struct WeatherData: Decodable {
let title: [WeatherItem]
}
struct WeatherItem: Decodable {
let title: String?
let value: String?
let condition: String?
public init(from decoder: Decoder) throws {
// decode the value for WeatherItem as [String]
let container = try decoder.singleValueContainer()
let components = try container.decode([String].self)
title = components.count > 0 ? components[0] : nil
value = components.count > 1 ? components[1] : nil
condition = components.count > 2 ? components[2] : nil
}
}
let json = """
{
"title": [
["Temperature", "9", "Good"],
["Visibility", "10 KM (6.2 Mi)", "Good"]
]
}
"""
let jsonData: Data = json.data(using: .utf8)!
let decoder = JSONDecoder()
let decoded = try! decoder.decode(WeatherData.self, from: jsonData)
debugPrint(decoded)
Комментарии:
1. но информация JSON постоянно меняется.
2. @DylanStrijker Структура меняется? Вы не указали это в своем вопросе! Что, вероятно, было бы лучше
WeatherItem
просто сохранить[String]
? Неясно, каков формат данных и какие операции вы выполняете над ними.3. Я имел в виду, что информация всегда меняется. Например, слово temperaturen будет таким же, но вторая строка будет изменяться.
4. @DylanStrijker Тогда я не вижу проблемы. Я только что использовал этот JSON в качестве примера того, как анализировать данные. Я думал, это будет очевидно.
5. хорошо, спасибо! Ваш пример работает, но я хотел бы использовать эту ссылку: virtualflight.ddns.net/api/weather.php?icao=ehrd как я могу это сделать с помощью ссылки? Я новичок в синтаксическом анализе JSON
Ответ №2:
Правильный json
{
"title": [
[
"Temperature",
" ",
"Good"
],
[
"Visibility",
"10 KM (6.2 Mi)",
"Good"
]
]
}
var arr = [WeatherItem]()
do {
let res = try JSONDecoder().decode([String:[[String]]].self, from: data)
let content = res["title"]!
content.forEach {
if $0.count >= 3 {
arr.append(WeatherItem(title:$0[0],value:$0[1],condition:$0[2]))
}
}
print(arr)
} catch {
print(error)
}
Обсуждение : ваш корневой объект — это словарь, который содержит 1 ключ с именем title
, а его значением является массив из массива строк или, исходя из логики модели, это массив с именем модели, WeatherItem
но не структурированный должным образом для него, поэтому, используя это
let weather = try JSONDecoder().decode(WeatherItem.self, from: data)
не будет работать, поскольку текущий json не содержит ключей value
и condition
Правильная структура была бы
[
{
"title":"Temperature" ,
"value":"",
"condition":"Good"
},
{
"title":"Visibility",
"title":"10 KM (6.2 Mi)",
"condition":"Good"
}
]
и это позволит вам сделать
let weather = try JSONDecoder().decode([WeatherItem].self, from: data)