Intereting Posts
Рисование пользовательской формы и анимация пользовательских свойств с помощью CALayers? Google Analytics Swift – не отображение обновленного отчета панели мониторинга Замена системы emoji на пользовательский emoji на iOS Измените команду подписи в Xcode 8 UITableView с несколькими массивами данных Изменение цвета излучателя частиц SpriteKit Каковы последствия изменения идентификатора пакета, идентификатора приложения и имени приложения для приложения в прямом эфире в магазине приложений Рефакторинг Swift alamofire пытается вернуть код состояния Утечки инструментов – Не отображается исходный код для устройства iPhone Установка текста UILabel не работает Как приложение «перехватывает» метод openURL в iOS? Изменения SQLite не сохранены Как играть сигнал с AudioUnit (iOS)? Достижимость в одном устройстве возвращает «NotReachable», несмотря на наличие 4G Выгрузить область из-за нового файла базы данных

JSON Parsing Help в Swift 4 – Проблема структуры данных?

Новые здесь и в Swift, поэтому, пожалуйста, пройдите на меня.

Немного застрял при попытке разбора JSON, который содержит вложенные словари. Я предполагаю, что это что-то не так со строками данных, которые я создал, и я попытался все исправить, но все еще получаю ту же проблему.

Это JSON api, с которой я пытаюсь работать: https://api.coindesk.com/v1/bpi/currentprice.json

Это структуры данных, которые я создал для моделирования этого:

struct base: Decodable { let disclaimer: String let bpi: [Bpi] } struct Bpi: Decodable { let USD: [USD] } struct USD: Decodable { let rate_float: Float } 

И вот мой код в VC:

  override func viewDidLoad() { super.viewDidLoad() let jsonURLString = "https://api.coindesk.com/v1/bpi/currentprice.json" 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 bitcoinData = try JSONDecoder().decode(base.self, from: data) print(bitcoinData.bpi) } catch { print("error") } } .resume() // Fires off the session } 

Я могу захватить данные из строки отказа или других строк в корневом словаре, но это все. Я не могу разобрать что-нибудь еще с вложенными диктаторами – он просто отбрасывает ошибку catch.

Вот JSON:

 { "time": { "updated": "Nov 2, 2017 06:08:00 UTC", "updatedISO": "2017-11-02T06:08:00+00:00", "updateduk": "Nov 2, 2017 at 06:08 GMT" }, "disclaimer": "This data was produced from the CoinDesk Bitcoin Price Index (USD). Non-USD currency data converted using hourly conversion rate from openexchangerates.org", "chartName": "Bitcoin", "bpi": { "USD": { "code": "USD", "symbol": "$", "rate": "6,889.4013", "description": "United States Dollar", "rate_float": 6889.4013 }, "GBP": { "code": "GBP", "symbol": "£", "rate": "5,184.4053", "description": "British Pound Sterling", "rate_float": 5184.4053 }, "EUR": { "code": "EUR", "symbol": "€", "rate": "5,910.4587", "description": "Euro", "rate_float": 5910.4587 } } } 

Я что-то явно делаю неправильно?

Спасибо за помощь заранее и извините, если мое форматирование отстой!

Solutions Collecting From Web of "JSON Parsing Help в Swift 4 – Проблема структуры данных?"

Попробуйте следующую модель, с этим она работает – и bpi и USD не являются массивами, а только одиночными значениями:

 struct base: Decodable { let disclaimer: String let bpi: Bpi } struct Bpi: Decodable { let USD: USD } struct USD: Decodable { let rate_float: Float } 

Словари ( Dictionary<K,V> ) неявно Decodable если оба универсальных типа K и V являются декодируемыми.

Предполагая, что вы создаете структуру Coin для валют

 struct Coin: Decodable { private enum CodingKeys : String, CodingKey { case code, symbol, rate, description, rateFloat = "rate_float" } let code : String let symbol : String let rate : String let description : String let rateFloat : Float } 

вы можете легко декодировать валютные словари как [String:Coin] без какого-либо дополнительного кода

 struct Base: Decodable { private enum CodingKeys : String, CodingKey { case disclaimer, coins = "bpi" } let disclaimer: String let coins: [String:Coin] } 

И использовать его

 let bitcoinData = try JSONDecoder().decode(Base.self, from: data) print(bitcoinData.coins) 

Альтернативно, если вы хотите, чтобы валюты как массив Coin вы можете написать собственный инициализатор и сопоставить значения словаря с массивом.

В этом примере также декодируется также updatedISO значениеISO во time словаре

 struct Base: Decodable { struct Time : Decodable { private enum CodingKeys : String, CodingKey { case updated = "updatedISO" } let updated : Date } private enum CodingKeys : String, CodingKey { case disclaimer, bpi, time } let disclaimer: String let coins: [Coin] let updated : Date init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) disclaimer = try container.decode(String.self, forKey: .disclaimer) let bpi = try container.decode([String:Coin].self, forKey: .bpi) coins = Array(bpi.values.sorted(by: {$0.code < $1.code})) let time = try container.decode(Time.self, forKey: .time) updated = time.updated } } 

И используйте этот пример

 let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 let bitcoinData = try decoder.decode(Base.self, from: data) print(bitcoinData.coins) 

Вы объявили свои свойства bpi & use как массивы, но они были словарями (вложенными объектами json). Если у вас есть образец JSON, вы можете попробовать этот конвертер в следующий раз: https://danieltmbr.github.io/JsonCodeGenerator/

Он генерирует следующий результат:

 struct Root: Codable { let time: Time let disclaimer: String let chartName: String let bpi: Bpi } struct Time: Codable { let updated: String let updatedISO: String let updateduk: String } struct Bpi: Codable { let USD: USD let GBP: USD let EUR: USD } struct USD: Codable { let code: String let symbol: String let rate: String let description: String let rateFloat: Double private enum CodingKeys: String, CodingKey { case code case symbol case rate case description case rateFloat = "rate_float" } }