I am new to coding and SwiftUI in general, I am coding a crypto portfolio app I am doing the candle stick chart using apple chart API, get my API data fetched. sorry if my code is messy.
JSON from market data rest API the "60" means the number of seconds and so on till the number of sec of 1 week with prices of the coin in the squared brackets
{
"result": {
"60": [
[
1665841920,
19131.1,
19131.8,
19131.1,
19131.8,
0.1343188,
2569.67054912
],
[
1665841980,
19130.8,
19130.8,
19130.8,
19130.8,
0.05614383,
1074.076382964
]
],
"180": [ ]
},
"allowance": {
"cost": 0.015,
"remaining": 7.33,
"upgrade": "For unlimited API access, create an account at https://cryptowat.ch"
}
}
here is my data model
import Foundation
import SwiftUI
// MARK: - Result
struct Result: Codable {
let result: [String: [[Double]]]?
let allowance: Allowance
}
// MARK: - Allowance
struct Allowance: Codable {
let cost, remaining: Double
let upgrade: String
}
here is my CoinNetworkManager where i do the networking
func loadData(){
// the url to request data from
let urlAlone = "https://api.cryptowat.ch/markets/kraken/btcusd/ohlc"
if let url = URL(string: urlAlone) {
// requesting data using URL session and dataTask, getting 3 parameters back, and put em in dat, response, error
// data is what the data we get back that we will be decoding and put em into our data object
let session = URLSession.shared
let task = session.dataTask(with: url){ data,response,error in
// if no error do this
// we will unwrap the optional data into unwrappedData and decode it using JSONDecoder
if error == nil{
print("task complete")
let decoder = JSONDecoder()
if let safeData = data {
do{
let decodedData = try decoder.decode(Result.self, from: safeData)
DispatchQueue.main.async {
// and pass the result to coinsData
self.result = decodedData
print(self.result.result?["3600"]?[1][2] ?? 0)
print(self.result.result?["3600"]?[1] ?? 0)
}
} catch {
print(error.localizedDescription)
}
}
}
}
task.resume()
}
}
printing above get me this in the console
19727.0 [1662278400.0, 19701.4, 19727.0, 19631.7, 19637.1, 24.43309418, 480989.386594268]
but when i try to put it in a chart i where i assume i will access through the index of the data array but i get: Fatal error: Index out of range how do i properly access the dict/ array [String:[Double]], was i formatted incorrectly or the method?
thank you in advance everyone 🙏
Chart code here
struct ContentView: View {
@ObservedObject var coinNM: CoinNetworkManager
// var pricesArray: [Double]
var body: some View {
// pricesArray = coinNM.result.result?["3600"] as! [Double]
VStack {
Chart(coinNM.result.result?["60"] ?? [[0.4],[0.5]], id: \.self) { price in
RectangleMark(x: .value("Close Time", price[0]),
yStart: .value("Low Price", price[1]),
yEnd: .value("High Price", price[0]), width: 4)
}
In ContentView
inside Chart
, try this approach where you check the price
(an array of Double) size, to solve your index out of range error:
Chart(coinNM.result.result?["60"] ?? [[0.4],[0.5]], id: \.self) { price in
if price.count > 1 { // <-- here
RectangleMark(x: .value("Close Time", price[0]),
yStart: .value("Low Price", price[1]), // <-- because
yEnd: .value("High Price", price[0]), width: 4)
}
}
Or this, depending on what you want to show:
Chart(coinNM.result.result?["60"] ?? [[0.4],[0.5]], id: \.self) { price in
if price.count > 3 { // <-- here
RectangleMark(x: .value("Close Time", price[0]),
yStart: .value("Low Price", price[3]), // <-- because
yEnd: .value("High Price", price[2]), width: 4)
}
}