SwiftUI JSON 解码器不工作(使用异步等待)

SwiftUI JSON Decoder not Working (using async await)

我正在创建现有应用程序的新版本并希望使用新的异步等待 Web 请求的格式。在 JSONDecoder().decode 行中断,我看到我确实有数据 - 但解码不起​​作用。 (url 和我的密钥在旧版本中有效)

这是网络资源的 JSON 格式(缩短 - 中还有更多项目 一个 fuel_station):

{
   "station_locator_url":"https://afdc.energy.gov/stations/",
   "total_results":110,
   "station_counts":{},
   "fuel_stations":[
      {
         "access_code":"public",
         "access_days_time":"24 hours daily; call 866-809-4869 for Clean Energy card",
         "access_detail_code":"KEY_ALWAYS",
         "cards_accepted":"CleanEnergy",
         "date_last_confirmed":"2021-09-10",
      }
   ]
}

我从上面创建了以下模型:

enum CodingKeys: String, CodingKey {
    case fuelStations = "fuel_stations"
    case accessCode = "access_code"
    case accessDaysTime = "access_days_time"
    case accessDetailCode = "access_detail_code"
    case cardsAccepted = "cards_accepted"
    case dateLastConfirmed = "date_last_confirmed"
}

struct TopLevel: Codable {
    let fuelStations: [FuelStation]
}

struct FuelStation: Codable {
    let accessCode, accessDaysTime, accessDetailCode, cardsAccepted: String
    let dateLastConfirmed: String
    let id: String
}

我将初始视图的简化版本放在一个文件中进行测试:

struct SiteListView: View {
    @State private var fuelStations: [FuelStation] = []
    @State private var topLevel: TopLevel = TopLevel(fuelStations: [])

    var body: some View {
        NavigationView {
            VStack {
                List(fuelStations, id: \.id) { item in
                    VStack {
                        Text(item.accessCode)
                        Text(item.accessDaysTime)
                    }
                }
            }
            .navigationTitle("Site List View")
            .task {
                await loadData()
            }
        }//nav
    }

    func loadData() async {
    
    //I believe the DEMO_KEY in the url will allow limited retrievals
        guard let url = URL(string: "https://developer.nrel.gov/api/alt-fuel-stations/v1.json?api_key=DEMO_KEY") else {
            print("Invalid URL")
            return
        }

        do {
            let (data, response) = try await URLSession.shared.data(from: url)
            guard (response as? HTTPURLResponse)?.statusCode == 200 else { return }
            print("response status code is 200")
        
            if let decodedResponse = try? JSONDecoder().decode(TopLevel.self, from: data) {
                topLevel = decodedResponse
                print("in decoding: topLevel.fuelStations.count is \(topLevel.fuelStations.count)")
                //I would iterate through topLevel here and add to the fuelStations 
                //array but I never get here
            }
        } catch {
            print("Invalid Data")
        }

    }//load data
}//struct

任何指导将不胜感激。 Xcode 13.2.1 iOS 15.2

首先你应该从 try? 中删除 ? 以便在像这样的解码出现问题时捕获工作

func loadData()  async {
   //I believe the DEMO_KEY in the url will allow limited retrievals
   guard let url = URL(string: "https://developer.nrel.gov/api/alt-fuel-stations/v1.json?api_key=DEMO_KEY") else {
       print("Invalid URL")
       return
   }

   do {
       let (data, response) = try await URLSession.shared.data(from: url)
       guard (response as? HTTPURLResponse)?.statusCode == 200 else { return }
       print("response status code is 200") 
       let decoder = JSONDecoder()
       decoder.keyDecodingStrategy = .convertFromSnakeCase
       let decodedResponse = try decoder.decode(TopLevel.self, from: data) 
       print("in decoding: topLevel.fuelStations.count is \(decodedResponse.fuelStations.count)")
       //I would iterate through topLevel here and add to the fuelStations
       //array but I never get here
       
   } catch {
       print(error)
   } 
}

执行此操作后,您会发现 struct 中的某些属性响应为空,因此您应该将 string 更改为 string? 最终为

struct TopLevel: Codable {
    let fuelStations: [FuelStation]
}

struct FuelStation: Codable {
    let accessCode, accessDaysTime, accessDetailCode, cardsAccepted,dateLastConfirmed: String?
    let id: Int
}

另外注意使用

   let decoder = JSONDecoder()
   decoder.keyDecodingStrategy = .convertFromSnakeCase

而不是硬编码 enum