SwiftUI中如何异步解析非数组格式的API JSON响应?
解决SwiftUI中非数组JSON解析的问题
直接错误的修复
初始化Response实例的错误
你的Response结构体没有默认初始化器(因为它的属性BillingAccount和TechnicalSupport都是自定义结构体,且没有默认值),所以不能直接用Response()创建实例。将results改为可选类型,初始值设为nil:@State private var results: Response?错误的赋值语句
解码后的decodedResponse本身就是Response类型的实例,它不存在Response这个成员属性。直接将解码结果赋值给results即可:results = decodedResponse
其他关键问题的修复(否则解析仍会失败)
除了上述两个直接错误,还有几个会导致解析失败或运行错误的问题:
数值类型不匹配:JSON中的
AccountBalance和TransactionCost是浮点数(如999.99),但你定义为Int,会导致解码失败。改为Double类型,同时新增ExtraInformation字段匹配JSON结构:struct BillingAccount: Codable { var AccountType: String var AccountBalance: Double var TransactionCost: Double var ExtraInformation: [String: Any]? }属性名与JSON字段不匹配:
JSON中的QueryDurationMs、SupportInformationList与你结构体中的属性名不一致,直接修改属性名与JSON保持一致:struct TechnicalSupport: Codable { var ServerId: String var RequestId: String var QueryDurationMs: Int var SupportDate: String var SupportTime: String var SupportCode: String var SupportInformationList: [String] }视图中属性访问路径错误:原来的
Text(results.AccountType)无法正确访问属性,需通过BillingAccount层级访问,同时处理可选值:Text(results?.BillingAccount.AccountType ?? "Loading...")URL变量名错误:URL字符串中使用的
domainName和apiKey与你定义的变量名domain、apikey不一致,修正后:guard let url = URL(string: "\(domain)/api/datapackage/\(type)?v=2&api_nullitems=1&auth_apikey=\(apikey)&key_content=\(content)") else { print("Invalid URL") return }错误处理优化:使用
try替代try?,这样能捕获并打印具体的解码错误,便于调试:do { let (data, _) = try await URLSession.shared.data(from: url) let decodedResponse = try JSONDecoder().decode(Response.self, from: data) results = decodedResponse } catch { print("解析错误: \(error)") }
完整修正后的代码
struct Response: Codable { var BillingAccount: BillingAccount var TechnicalSupport: TechnicalSupport } struct BillingAccount: Codable { var AccountType: String var AccountBalance: Double var TransactionCost: Double var ExtraInformation: [String: Any]? } struct TechnicalSupport: Codable { var ServerId: String var RequestId: String var QueryDurationMs: Int var SupportDate: String var SupportTime: String var SupportCode: String var SupportInformationList: [String] } struct ContentView: View { @State private var results: Response? let domain = "https://www.domainName.co" @State var type: String = "type" @State var apikey: String = "apiKey" @State var content: String = "content" var body: some View { Text(results?.BillingAccount.AccountType ?? "Loading...") .task { await loadData() } } func loadData() async { guard let url = URL(string: "\(domain)/api/datapackage/\(type)?v=2&api_nullitems=1&auth_apikey=\(apikey)&key_content=\(content)") else { print("Invalid URL") return } do { let (data, _) = try await URLSession.shared.data(from: url) let decodedResponse = try JSONDecoder().decode(Response.self, from: data) results = decodedResponse } catch { print("解析错误: \(error)") } } }
问题原因总结
- 自定义结构体没有默认初始化器,无法直接创建空实例;
- 错误地尝试访问解码结果中不存在的
Response成员; - 结构体属性类型、名称与JSON字段不匹配,导致解码失败;
- 视图中属性访问路径错误,且未处理可选值;
- URL构建时变量名拼写错误,导致无效URL。
内容的提问来源于stack exchange,提问作者Sam Staples
相关产品推荐
相关产品推荐

