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

Swift中JSONDecode解码数组/字典失败问题求助

解决Swift中JSONDecoder解码地震API返回数据的类型不匹配问题

你的错误提示已经说得很清楚了:你尝试把返回的JSON解码成[earthquakeResults].self(数组类型),但实际API返回的是一个包含earthquakes数组的顶层字典,这就导致了类型不匹配的崩溃。下面是具体的修复步骤:

1. 调整Codable结构体定义

首先,我们需要定义一个顶层结构体来匹配API返回的JSON结构,同时修正结构体的命名(遵循Swift大驼峰命名规范),并补全原来注释的字段(API返回的eqid和src都是字符串类型,不需要用Any):

// 匹配API返回的顶层字典结构
struct EarthquakeResponse: Codable {
    let earthquakes: [EarthquakeResult]
}

// 单个地震数据的结构体
struct EarthquakeResult: Codable {
    let datetime: String
    let depth: String
    let eqid: String
    let lat: String
    let lng: String
    let magnitude: String
    let src: String
}

2. 修改解码逻辑

接下来调整你的网络请求完成后的解码代码,主要做这几个优化:

  • 用do-catch替代危险的try!,避免解码失败直接崩溃
  • 解码顶层的EarthquakeResponse结构体,再取出内部的地震数组
  • 安全处理数组为空的情况,避免索引越界

修改后的代码如下:

let urlAsString = "http://api.geonames.org/earthquakesJSON?north=\(north)&south=\(south)&east=\(east)&west=\(west)&username=antoniogomez"
guard let url = URL(string: urlAsString) else {
    print("Invalid URL")
    return
}

let urlSession = URLSession.shared
let jsonQuery = urlSession.dataTask(with: url, completionHandler: { data, response, error -> Void in
    // 处理请求错误
    if let error = error {
        print(error.localizedDescription)
        return
    }
    
    // 确保数据不为空
    guard let data = data else {
        print("No data received from API")
        return
    }
    
    do {
        let decoder = JSONDecoder()
        // 解码顶层的EarthquakeResponse
        let apiResponse = try decoder.decode(EarthquakeResponse.self, from: data)
        let earthquakeResults = apiResponse.earthquakes
        
        print("Fetched \(earthquakeResults.count) earthquakes")
        
        // 安全获取第一个地震数据(避免数组为空时崩溃)
        if let firstEarthquake = earthquakeResults.first {
            let dt = firstEarthquake.datetime
            let dp = firstEarthquake.depth
            let lt = firstEarthquake.lat
            let lg = firstEarthquake.lng
            let mag = firstEarthquake.magnitude
            let res = "Results : \(dt) \(dp) \(lt) \(lg) \(mag)"
            print(res)
        } else {
            print("No earthquakes found in the requested area")
        }
        
    } catch {
        // 捕获并打印解码错误
        print("JSON Decoding Error: \(error.localizedDescription)")
        print("Detailed error info: \(error)")
    }
})
jsonQuery.resume()

额外说明

  • 你之前用JSONSerialization无法获取字段的原因,大概率也是因为没有先从顶层字典中取出earthquakes数组,直接去取字段当然找不到。
  • 永远不要用try!处理解码操作,一旦API返回结构变化或数据异常,你的App会直接崩溃,do-catch是更安全的处理方式。
  • Swift的Codable对字符串、数字等基础类型的兼容性很好,只要API返回的字段类型和你定义的结构体字段类型匹配,就能正常解码。

内容的提问来源于stack exchange,提问作者Code Gomez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 11:32:48