Iam trying to display the contents of the result. The Data is returned as JSON Array. I created a view model "Stocks" and want to access the "results". Currently it compiles but the data does not show up.
Help would be highly appreciated
import SwiftUI
struct Stocks: Hashable, Codable{
var results: [Results]
var status: String
struct Results: Hashable, Codable{
var ticker: String
var name: String
var market: String
var locale: String
var primary_exchange: String
var type: String
var active: Bool
var currency_name: String
var cik: String
var composite_figi: String
var share_class_figi: String
var last_update_utc: String
}
}
class ViewModel: ObservableObject{
@Published var stocks: [Stocks] = []
func fetch(){
guard let url = URL(string: "https://api.polygon.io/v3/reference/tickers?market=stocks&active=true&apiKey=<apikey>") else{return}
let task = URLSession.shared.dataTask(with: url) {[weak self]data, _, error in
guard let data = data, error == nil else{
return
}
// Convert JSON
do{
let stocks = try JSONDecoder().decode([Stocks].self, from: data)
DispatchQueue.main.async{
self?.stocks = stocks
}
}
catch{
print(error)
}
}
task.resume()
}
}
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
NavigationView{
List{
ForEach(viewModel.stocks, id: \.self){resu in
ForEach(resu.results, id: \.self){st in
Text(st.currency_name)
}
}
}
}.navigationTitle("Stocks")
.onAppear{
viewModel.fetch()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Here is the Response object:
{
"results": [
{
"ticker": "A",
"name": "Agilent Technologies Inc.",
"market": "stocks",
"locale": "us",
"primary_exchange": "XNYS",
"type": "CS",
"active": true,
"currency_name": "usd",
"cik": "0001090872",
"composite_figi": "BBG000C2V3D6",
"share_class_figi": "BBG001SCTQY4",
"last_updated_utc": "2022-12-20T00:00:00Z"
},
{
"ticker": "AA",
"name": "Alcoa Corporation",
"market": "stocks",
"locale": "us",
"primary_exchange": "XNYS",
"type": "CS",
"active": true,
"currency_name": "usd",
"cik": "0001675149",
"composite_figi": "BBG00B3T3HD3",
"share_class_figi": "BBG00B3T3HF1",
"last_updated_utc": "2022-12-20T00:00:00Z"
},
I created a view model "Stocks" and want to access the "results". Currently it compiles but the data does not show up.
CodePudding user response:
The naming of your structs is largely confusing.
According to the JSON you are going to receive one root object containing an array of Stock
(supposed to be named in singular form) objects for key results
.
And there is a struct member last_update_utc
which does not match the key last_updated_utc
.
Name your structs this way, I renamed the struct members as camelCase and as constants (let
) and you can decode lastUpdatedUtc
as Date
with the .iso8601
strategy
struct Response: Hashable, Decodable {
let results: [Stock]
let status: String
struct Stock: Hashable, Decodable {
let ticker: String
let name: String
let market: String
let locale: String
let primaryExchange: String
let type: String
let active: Bool
let currencyName: String
let cik: String
let compositeFigi: String
let shareClassFigi: String
let lastUpdatedUtc: Date
}
}
and decode the JSON
class ViewModel: ObservableObject{
@Published var stocks: [Response.Stock] = []
func fetch() {
guard let url = URL(string: "https://api.polygon.io/v3/reference/tickers?market=stocks&active=true&apiKey=<apikey>") else{return}
let task = URLSession.shared.dataTask(with: url) {[weak self] data, _, error in
if let error { print(error); return }
// Convert JSON
do{
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .iso8601
let response = try decoder.decode(Response.self, from: data!)
DispatchQueue.main.async {
self?.stocks = response.results
}
}
catch{
print(error)
}
}
task.resume()
}
}
I even recommend to use async/await
@MainActor
class ViewModel: ObservableObject{
@Published var stocks: [Response.Stock] = []
func fetch() {
guard let url = URL(string: "https://api.polygon.io/v3/reference/tickers?market=stocks&active=true&apiKey=<apikey>") else{return}
Task {
do {
let (data, _) = try await URLSession.shared.data(from: url)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .iso8601
let response = try decoder.decode(Response.self, from: data)
self.stocks = response.results
} catch {
print(error)
}
}
}
}