Swift JSON解码失败:期望数组却得到字典的问题求助
Swift JSON解码类型不匹配问题解决方法
问题描述
我知道这类问题有不少解答,但实在解决不了。尝试将JSON数据解码到自定义结构体中,推测问题出在数据模型,但无法确定。返回的JSON并非数组,内部仅包含一个数组。当前代码试图将字典解码为数组,若将results变量初始化为非数组类型则无法编译。附上代码与JSON数据寻求帮助。
报错信息
JSON decode failed: Swift.DecodingError.typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))
现有代码
import SwiftUI struct DataFormatted: Codable, Hashable { var deliveryPoints: [DeliveryPoints] var deliveryPointCount: Int var postalCounty: String var traditionalCounty: String var town: String var postCode: String } struct DeliveryPoints: Codable, Hashable { var organisationName: String var departmentName: String var line1: String var line2: String var udprn: String var dps: String } struct ContentView: View { // 我认为问题在这里: @State private var results = [DataFormatted]() var body: some View { VStack{ List{ ForEach(results, id: \.self) { result in Text(result.postalCounty) } } } .task { await loadData() } } func loadData() async { guard let url = URL(string: "https://pcls1.craftyclicks.co.uk/json/rapidaddress?key=APIKEY&postcode=aa11aa&response=data_formatted") else { print("Invalid URL") return } var request = URLRequest(url: url) request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpMethod = "GET" do { let (data, _) = try await URLSession.shared.data(for: request) let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase let decodedResponse = try decoder.decode([DataFormatted].self, from: data) results = decodedResponse } catch let jsonError as NSError { print("JSON decode failed: \(jsonError)") } } }
返回的JSON数据
{ "delivery_points":[ { "organisation_name":"THE BAKERY", "department_name":"", "line_1":"1 HIGH STREET", "line_2":"CRAFTY VALLEY", "udprn":"12345678", "dps":"1A" }, { "organisation_name":"FILMS R US", "department_name":"", "line_1":"3 HIGH STREET", "line_2":"CRAFTY VALLEY", "udprn":"12345679", "dps":"1B" } ], "delivery_point_count":2, "postal_county":"POSTAL COUNTY", "traditional_county":"TRADITIONAL COUNTY", "town":"BIG CITY", "postcode":"AA1 1AA" }
解决方案
核心问题:你错误地将顶层JSON字典当作数组解码,同时results的类型定义不符合JSON结构。
1. 修正数据存储变量类型
将ContentView中的results变量从数组类型改为可选的单个实例:
@State private var result: DataFormatted?
2. 修改解码逻辑
在loadData函数中,把解码数组的代码改为解码单个DataFormatted对象:
let decodedResponse = try decoder.decode(DataFormatted.self, from: data) result = decodedResponse
3. 更新UI展示逻辑
由于result是可选类型,需要安全解包后再展示内容,修改List部分代码:
List{ if let result = result { Text(result.postalCounty) // 若需展示配送点列表,可嵌套ForEach: ForEach(result.deliveryPoints, id: \.self) { point in Text(point.line1) } } }
补充说明
- 你的
DataFormatted结构体定义完全匹配JSON结构,配合convertFromSnakeCase解码策略,可自动处理JSON下划线命名到Swift驼峰命名的转换,无需修改结构体属性名。 - 原代码报错的本质是顶层JSON是单个对象(字典),却被当作数组解码,调整解码目标类型即可解决问题。
内容的提问来源于stack exchange,提问作者Layth Tameem
相关产品推荐
相关产品推荐

