You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 15:50:38