【问题标题】:Parsing a Stock API that contain dates as keys using the Codable protocol使用 Codable 协议解析包含日期作为键的 Stock API
【发布时间】:2019-06-06 21:20:53
【问题描述】:

我正在尝试解析来自 Alpha Vantage 的股票 api。 这是响应的样子:API Response Demo

我设置了四个类用于解码和编码:

  1. 股票
  2. 元数据
  3. 时间序列
  4. 高开低收

我认为问题出在时间序列类中,因为我想将数组日期作为键,每个日期都包含打开、关闭、高、低值。所有三个类都符合Codable 协议。我更改了枚举中​​键的值,以便它可以匹配正确的JSON Response

    var stocks = [Stocks]()
override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .red
    loadURL()
}


func loadURL(){
    let stocksURL = URL(string: "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=5min&apikey=demo")
    print("Inside loadURL")
    guard let url = stocksURL else { return }
    if let data = try? Data(contentsOf: url){
        print("Inside data")
        parse(json: data)
    }
}

func parse(json: Data){
    let jsonDecoder = JSONDecoder()
    print("before Decoding")
    if let json = try? jsonDecoder.decode([Stocks].self, from: json){
        print("Inside parsing")
        stocks = json
        print(stocks[0].meta_data.symbol)
        print(stocks[0].time_series.OHLC[0].open)
    }
}
}

class Stocks: Codable {
var meta_data: MetaData
var time_series: TimeSeries

enum CodingKeys: String, CodingKey {
    case meta_data   = "Meta Data"
    case time_series = "Time Series (5min)"
}
}

class MetaData: Codable {
var information: String
var symbol: String
var lastRefreshed: String
var outputSize: String
var timeZone: String

enum CodingKeys: String, CodingKey {
    case information   = "1. Information"
    case symbol        = "2. Symbol"
    case lastRefreshed = "3. Last Refreshed"
    case outputSize    = "4. Output Size"
    case timeZone      = "5. Time Zone"
}
}

class TimeSeries: Codable {
var OHLC: [OpenHighLowClose]
}

class OpenHighLowClose: Codable {
var open: Double
var high: Double
var low: Double
var close: Double
var volume: Double

enum CodingKeys: String, CodingKey {
    case open   = "1. open"
    case high   = "2. high"
    case low    = "3. low"
    case close  = "4. close"
    case volume = "5. volume"
}
}

【问题讨论】:

  • 与您的问题无关,但从不使用Data(contentsOf:) 在主队列上加载远程数据。很坏。使用URLSession 获取数据。正确接受加载远程数据的异步特性。

标签: json swift parsing codable


【解决方案1】:

这里是正确的数据类型 w.r.t 您的响应

// MARK: - Response
struct Response: Codable {
    let metaData: MetaData
    let timeSeries5Min: [String: TimeSeries5Min]

    enum CodingKeys: String, CodingKey {
        case metaData = "Meta Data"
        case timeSeries5Min = "Time Series (5min)"
    }
}

// MARK: - MetaData
struct MetaData: Codable {
    let the1Information, the2Symbol, the3LastRefreshed, the4Interval: String
    let the5OutputSize, the6TimeZone: String

    enum CodingKeys: String, CodingKey {
        case the1Information = "1. Information"
        case the2Symbol = "2. Symbol"
        case the3LastRefreshed = "3. Last Refreshed"
        case the4Interval = "4. Interval"
        case the5OutputSize = "5. Output Size"
        case the6TimeZone = "6. Time Zone"
    }
}

// MARK: - TimeSeries5Min
struct TimeSeries5Min: Codable {
    let the1Open, the2High, the3Low, the4Close: String
    let the5Volume: String

    enum CodingKeys: String, CodingKey {
        case the1Open = "1. open"
        case the2High = "2. high"
        case the3Low = "3. low"
        case the4Close = "4. close"
        case the5Volume = "5. volume"
    }
}

用法:

  func loadURL() {
    let stocksURL = URL(string: "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=5min&apikey=demo")
    URLSession.shared.dataTask(with: stocksURL!) { (data, response, error) in
      if let error = error {
        print(error)
        return
      }
      do {
        let response = try JSONDecoder().decode(Response.self, from: data!)
        response.timeSeries5Min.forEach({ (keyValue) in
          print(keyValue)
        })
      } catch {
        print(error)
      }
    }.resume()
  }

【讨论】:

  • 所以有一个原因为什么最好在 Data(contentsOf: url) 上做一个 URLSession 。似乎做 Data(contentsOf) 会更具可读性。我还是新手,所以只是想知道。
  • 您应该异步加载数据,以便您的应用在加载过程中不会看起来卡住。您应该注意到,当您使用 if let data = try? Data(contentsOf: url) { 加载数据时,您的应用会因为未收到响应而卡住,这对用户体验不利。
  • 您可以在异步获取数据时显示活动指示器/微调器。
猜你喜欢
  • 2018-04-26
  • 2019-07-16
  • 1970-01-01
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 2013-11-08
  • 1970-01-01
相关资源
最近更新 更多