Как проанализировать данные json, которые имеют пару словарь: значение? Я пытаюсь извлечь пару символ и значение - PullRequest
0 голосов
/ 22 января 2020

Как правильно проанализировать следующие json данные? Моя проблема на линии: if let rates = data["rates"] as? NSDictionary...

Данные json

{   "valid": true,   
    "timestamp": 1579683079,   
    "base": "USD",  
    "rates": {
       "AED": 3.67316,
       "AFN": 77.99911,
       "ALL": 110.11741,
       ...
       "ZAR": 14.45,
       "ZMW": 14.63257   
     } 
 }

Код

import UIKit

struct CurrencyRate {
    var valid: String
    var timestamp: Int
    var base: String
    var rates: [String:Double] = [:]
}

class ViewController: UIViewController {

var mySymbols:[String] = []
var myValues:[Double] = []


override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    let jsonUrlString = "https://currencyapi.net/api/v1/rates?key=6b171cc58787d922eb53e3684d97784d165a&base=USD"

    guard let url = URL(string: jsonUrlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, response, err) in
        guard let data = data else { return }

        //let dataAsString = String(data: data, encoding: .utf8)
        if let rates = data["rates"] as? NSDictionary {
            for (key, value) in rates {
                self.mySymbols.append((key as? String)!)

                self.myValues.append((value as? Double)!)
            }
        }


    }.resume()

}

}

Ответы [ 2 ]

2 голосов
/ 22 января 2020

Синтаксис

for (key, value) in ...

для перечисления словаря существует только для собственных словарей Swift.

Это должно работать, если вы приведете к указанному c [String:Double], который вы даже Избавьтесь от уродливых типов key и value.

if let rates = data["rates"] as? [String:Double] {
    for (key, value) in rates {
        self.mySymbols.append(key)
        self.myValues.append(value)
    }
}

Однако вам рекомендуется использовать протокол Decodable для анализа JSON. Есть только несколько незначительных изменений.

struct CurrencyRate : Decodable {
    let valid: Bool // must be Bool
    let timestamp: Date 
    let base: String
    let rates: [String:Double]
}

var rates = [String:Double]()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.

    let jsonUrlString = "https://currencyapi.net/api/v1/rates?key=6b171cc58787d922eb53e3684d97784d165a&base=USD"

    guard let url = URL(string: jsonUrlString) else { return }

    URLSession.shared.dataTask(with: url) { (data, _, error) in
        guard let error = error else { print(error); return }

        do {
           let decoder = JSONDecoder()
           decoder.dateDecodingStrategy = .secondsSince1970
           let result = try decoder.decode(CurrencyRate.self, from: data!)
           self.rates = result.rates
           print(rates)
        } catch {
            print(error)
        }
    }.resume()   
}

timestamp декодируется как Date

1 голос
/ 22 января 2020

Не используйте NSDictionary - используйте тип Dictionary в Swift. Кроме того, у вас есть data, и это совсем не словарь. Это Data тип. Использование должно преобразовать ваши данные в ваш тип. Попробуйте использовать этот код:

URLSession.shared.dataTask(with: url) { (data, response, err) in
    guard let data = data else { return }

    let jsonResult = try? JSONSerialization.jsonObject(with: data)

    if let dict = jsonResult as? Dictionary<String, Any>, let rates = dict["rates"] as? Dictionary<String, Double> {
        for (key, value) in rates {
            print(key, value)
            self.mySymbols.append(key)
            self.myValues.append(value)
        }
    }
}.resume()

Есть способ с Codable, но я думаю, это будет следующий вызов для вас. Кроме того, имейте в виду, что код выполняется асинхронно, и данные в глобальных переменных не появятся сразу

...