用于ListView的Swift JSON嵌套输出

vlf7wbxs  于 2022-12-21  发布在  Swift
关注(0)|答案(1)|浏览(109)

我试图显示结果的内容。数据以JSON数组的形式返回。我创建了一个视图模型“股票”,并希望访问“结果”。目前它编译,但数据没有显示。
如果你能提供帮助

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

下面是Response对象:

{
    "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"
        },

我创建了一个视图模型“股票”,并希望访问“结果”。目前它编译,但数据没有显示。

vqlkdk9b

vqlkdk9b1#

结构体的命名在很大程度上是混乱的。
根据JSON,您将收到一个根对象,其中包含一个Stock(假定以单数形式命名)对象数组,用于键results
并且存在与键last_updated_utc不匹配的结构成员last_update_utc
这样命名结构体,我将结构体成员重命名为camelCase和常量(let),您可以使用.iso8601策略将lastUpdatedUtc解码为Date

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

并解码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()
    }
}

我甚至推荐使用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)
            }
        }
    }
}

相关问题