【问题标题】:Want to view json metadata想查看json元数据
【发布时间】:2018-07-22 16:40:35
【问题描述】:

我正在尝试使用适用于 iOS 的 Alpha Vantage API 构建一个显示货币汇率的应用。我已经构建了函数,但无法弄清楚如何访问确切的 json 值,即“5. Exchange Rate”。

这里是一些代码和 json 数据,以帮助更好地解释:

建立的网址:

func USDtoEUR(_ completionHandler: @escaping (_ success: Bool, _ quotes: [String:AnyObject]?, _ error: String?) -> Void) {

    let urlString = "https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=USD&to_currency=EUR&apikey=NP3M8LL62YJDO0YX"
        let session = URLSession.shared
        let url = URL(string: urlString)!

        let request = URLRequest(url: url)
        let task = session.dataTask(with: request, completionHandler: { data, response, error in
            if error != nil {
                completionHandler(false, nil, error!.localizedDescription)
            }
            else {
                do {
                    let result = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
                    if let dictionary = result["Realtime Currency Exchange Rate"] as? [String:AnyObject]! {
                        completionHandler(true, dictionary, nil)
                    }
                    else {
                        completionHandler(false, nil, nil)
                    }
                } catch {
                    completionHandler(false, nil, "Unable to process retrieved data.")
                }
            }

        })
        task.resume()

    }

视图控制器中的引号

func usdQUotesRequest() {

  USDClient().USDtoEUR() { success, newQuote, error in

    if success {
        self.usdtoeurquote = newQuote
        DispatchQueue.main.async {
            self.stopActivityIndicator()
            self.Refresh.isEnabled = true
        }

    } else {
        DispatchQueue.main.async {
            self.displayAlert("Unable to Retrieve Latest Conversion Rates", message: "\(error!)")
            self.stopActivityIndicator()
            self.Refresh.isEnabled = true

        }
    }
}

// 触摸美元按钮后显示的报价:

@IBAction func usdConversions(_ sender: Any) {

    self.displayAlert("Alert!", message: "USD Selected")

    let usdVal = (outputCurrency1.text! as NSString).floatValue

    let euroValue = usdVal * (usdtoeurquote["5. Exchange Rate"] as! Float)
    outputCurrency2.text = String(format: "%.2f", euroValue)

    let gbpVal = usdVal * (usdtogbpquote["5. Exchange Rate"] as! Float)
    outputCurrency3.text = String(format: "%.2f", gbpVal)

    let cnyVal = usdVal * (usdtocnyquote["5. Exchange Rate"] as! Float)
    outputCurrency2.text = String(format: "%.2f", cnyVal)

    let cadVal = usdVal * (usdtocadquote["5. Exchange Rate"] as! Float)
    outputCurrency2.text = String(format: "%.2f", cadVal)

    let inrVal = usdVal * (usdtoinrquote["5. Exchange Rate"] as! Float)
    outputCurrency2.text = String(format: "%.2f", inrVal)

    let sekVal = usdVal * (usdtosekquote["5. Exchange Rate"] as! Float)
    outputCurrency2.text = String(format: "%.2f", sekVal)

    let rubVal = usdVal * (usdtorubquote["5. Exchange Rate"] as! Float)
    outputCurrency2.text = String(format: "%.2f", rubVal)

    let nzdVal = usdVal * (usdtonzdquote["5. Exchange Rate"] as! Float)
    outputCurrency2.text = String(format: "%.2f", nzdVal)

}

原始 JSON 数据:The json data on the webpage

【问题讨论】:

  • 首先,Swift 3+ 中的 JSON 字典是 [String:Any]。请(学习)阅读 JSON。这很简单。例如,双引号中的所有内容都是String(没有例外)。所以键5. Exchange Rate 的值是String,而不是Float。此外,我建议使用Decodable 协议将 JSON 解析为结构。
  • 所以不能用只能下载的值做任何计算?
  • 可以,但必须从String 创建DoubleFloat(但请不要通过NSString > floatValue
  • 好的,谢谢,那么为什么每次我尝试下载它找不到可选值的值时都会说? json序列化是否正确?
  • usdConversions 出现异常,因为如前所述,费率是字符串,而不是浮点数。不要使用NSDictionary,转换为[String:Any],键Realtime Currency Exchange Rate 的值实际上更具体[String:String]。并省略options 参数。 .allowFragments 在这种情况下毫无意义。

标签: json swift xcode api alpha-vantage


【解决方案1】:

主要错误是键 5. Exchange Rate 的值是 String 而不是 Float 并且代码在被强制解包时可靠地崩溃。

在 Swift 4 中,Decodable 协议比字典方便得多。

创建两个结构。 ExchangeRate 结构包含计算属性 floatRate 以返回 Float

struct Root : Decodable {
    let exchangeRate : ExchangeRate
    private enum  CodingKeys: String, CodingKey { case exchangeRate = "Realtime Currency Exchange Rate" }
}

struct ExchangeRate : Decodable {

    let fromCode, fromName, toCode, toName, rate : String
    let lastRefreshed, timeZone : String

    private enum  CodingKeys: String, CodingKey {
        case fromCode = "1. From_Currency Code"
        case fromName = "2. From_Currency Name"
        case toCode = "3. To_Currency Code"
        case toName = "4. To_Currency Name"
        case rate = "5. Exchange Rate"
        case lastRefreshed = "6. Last Refreshed"
        case timeZone = "7. Time Zone"
    }

    var floatRate : Float {
        return Float(rate) ?? 0.0
    }
}

然后通过传递 fromto 货币作为参数,使下载功能更加通用。此版本使用JSONDecoder 并返回ExchangeRate 实例或Error

func downloadRate(from: String, to: String, completionHandler: @escaping (ExchangeRate?, Error?) -> Void) {

    let urlString = "https://www.alphavantage.co/query?function=CURRENCY_EXCHANGE_RATE&from_currency=\(from)&to_currency=\(to)&apikey=NP3M8LL62YJDO0YX"
    let task = URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { data, response, error in
        if error != nil {
            completionHandler(nil, error!)
        } else {
            do {
                let result = try JSONDecoder().decode(Root.self, from: data!)
                completionHandler(result.exchangeRate, nil)
            } catch {
                completionHandler(nil, error)
            }
        }
    })
    task.resume()
}

并使用它

func usdQUotesRequest() {

  USDClient().downloadRate(from:"USD", to: "EUR") { exchangeRate, error in

    if let exchangeRate = exchangeRate {
        self.usdtoeurquote = exchangeRate.floatRate
        DispatchQueue.main.async {
            self.stopActivityIndicator()
            self.Refresh.isEnabled = true
        }
    } else {
        DispatchQueue.main.async {
            self.displayAlert("Unable to Retrieve Latest Conversion Rates", message: "\(error!)")
            self.stopActivityIndicator()
            self.Refresh.isEnabled = true
        }
    }
}

【讨论】:

  • 哦,谢谢!在 self.usdtoeurquote = exchangeRate.floarRate 方面,但是我收到一个错误:无法分配“Float”类型的值?键入“[字符串:任何]”。我将 usdtoeurqutoe 声明为 var usdtoeurquote = [String:Any]()。现在怎么了?
  • 我的代码用自定义结构替换了字典。如果您对解码后的 JSON 的所有字段感兴趣,请将 usdtoeurquote 声明为 ExchangeRate 分配结构实例,否则为 Float 并分配速率。
  • 是的,它成功了!非常感谢!我仍然收到警告 var usdtoeurquote = ExchangeRate.init(fromCode: "1. From_Currency Code", fromName: "2. From_Currency Name", toCode: "3. To_Currency Code", toName: "4. To_Currency Name", rate: "5. Exchange Rate", lastRefreshed: "6. Last Refreshed", timeZone: "7. Time Zone") as? Float,即“从 'ExchangeRate' 转换为不相关的类型 'Float' 总是失败”。
  • 不要将ExchangeRate 转换为Float,它们是两种完全不同的类型。请完全使用我的代码 (self.usdtoeurquote = exchangeRate.floatRate)。 ExchangeRate 结构有一个计算属性 floatRate,它返回一个从解码的 rate 字符串创建的 Float
猜你喜欢
  • 1970-01-01
  • 2014-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多