Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.1k views
in Technique[技术] by (71.8m points)

json - Parsing a Stock API that contain dates as keys using the Codable protocol

I am trying to parse a stock api from Alpha Vantage. This is what a response looks like: API Response Demo

I set up Four classes to use for decoding and encoding:

  1. Stocks
  2. Meta Data
  3. Time Series
  4. Open High Low Close

I think the problem lies in the Time Series Classes since i am suppose to be getting an array dates as a Key, which each contain Open, Close, High, Low values. All three classes conform to the Codable protocol.I changed the value of the keys in the enum so that it could match the correct 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"
}
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here are the proper data types w.r.t your response

// 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"
    }
}

Usage:

  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()
  }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...