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

Swift 4中使用Decodable访问嵌套JSON的技术问题

解决Swift解析嵌套JSON数组的问题

嘿,我来帮你搞定这个嵌套JSON数组解析的问题!首先得搞清楚你要处理的JSON结构,然后通过创建顶层解析模型来拿到目标数组,具体步骤如下:

先明确问题背景

你已经定义了StarWarsPeople模型,但卡在了如何从JSON的嵌套数组里取出数据来初始化这些对象。假设你调用的是Star Wars的API,返回的JSON结构大概是这样的(核心是数组嵌套在results字段里):

{
  "count": 82,
  "next": "https://swapi.dev/api/people/?page=2",
  "previous": null,
  "results": [
    {
      "name": "Luke Skywalker",
      "height": "172",
      "mass": "77",
      "hair_color": "blond",
      // 其他对应字段...
    }
  ]
}

步骤1:创建顶层响应模型

因为目标数组是嵌套在顶层字典里的,所以我们需要先定义一个承接整个JSON响应的Decodable结构,这样才能顺利拿到里面的数组:

struct StarWarsResponse: Decodable {
    let results: [StarWarsPeople]
}

步骤2:完善APIClient的解析逻辑

接下来修改你的StarWarsPeopleAPIClient,发起网络请求后用JSONDecoder先解析整个顶层响应,再取出里面的results数组:

class StarWarsPeopleAPIClient {
    class func fetchPeople(completion: @escaping ([StarWarsPeople]?, Error?) -> Void) {
        // 替换成你实际的API地址
        guard let url = URL(string: "https://swapi.dev/api/people/") else {
            completion(nil, NSError(domain: "Invalid URL", code: 0, userInfo: [NSLocalizedDescriptionKey: "URL格式错误"]))
            return
        }
        
        URLSession.shared.dataTask(with: url) { data, _, error in
            // 先处理网络错误
            if let error = error {
                completion(nil, error)
                return
            }
            
            // 确保拿到数据
            guard let responseData = data else {
                completion(nil, NSError(domain: "Data Error", code: 0, userInfo: [NSLocalizedDescriptionKey: "未获取到数据"]))
                return
            }
            
            do {
                // 解析顶层响应
                let swResponse = try JSONDecoder().decode(StarWarsResponse.self, from: responseData)
                // 取出嵌套的人物数组,传给回调
                completion(swResponse.results, nil)
            } catch let decodingError {
                completion(nil, decodingError)
            }
        }.resume()
    }
}

额外的小修正

注意你的StarWarsPeople里的weight属性,Star Wars API对应的字段是mass,如果不想改属性名,需要添加CodingKeys来做字段映射:

class StarWarsPeople: Decodable {
    var name: String?
    var height: String?
    var weight: String?
    var hair_color: String?
    var skin_color: String?
    var eye_color: String?
    var birth_year: String?
    var gender: String?
    
    // 字段映射,解决属性名和API字段名不一致的问题
    enum CodingKeys: String, CodingKey {
        case name, height, hair_color, skin_color, eye_color, birth_year, gender
        case weight = "mass"
    }
}

另外建议把StarWarsPeople改成struct,值类型在处理数据模型时更安全,而且默认就能自动合成Decodable的实现,不需要额外代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 04:32:31