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

iOS开发:如何用Alamofire解析JSON Codable数组

如何用Alamofire解析JSON数组的Codable数据

核心问题分析

你的解析失败主要源于以下几个不匹配:

  • API返回的是直接的Order对象数组,但你试图用OrderList结构体去解析,结构不匹配
  • Order的CodingKeys使用了大写的Name/Email等键,但API返回的是小写的name/email,键名不匹配
  • coffeeSize枚举定义的CodingKeys是映射s/m/l,但API返回的是完整的small/medium/large,枚举解析逻辑错误
  • 解析代码绕了弯路,没必要先转成JSON再序列化数据,Alamofire原生支持直接解析Codable

修正步骤及代码

1. 修正模型结构

去掉多余的OrderList,直接用[Order]接收数组;修正CodingKeys匹配API返回的键名;修正coffeeSize的解析逻辑;去掉不必要的隐式解包:

// 咖啡类型枚举,rawValue匹配API返回的字符串
enum CoffeeType: String, Codable {
    case cappuccino = "Cappuccino"
    case lattee = "Lattee"
    case espressino = "Espressino"
    case cortado = "Cortado"
}

// 咖啡尺寸枚举,直接匹配API返回的字符串,无需自定义CodingKeys
enum CoffeeSize: String, Codable {
    case small, medium, large
}

struct Order: Codable {
    let email: String
    let name: String
    let size: CoffeeSize
    let type: CoffeeType
    
    // 键名完全匹配API返回的小写字段
    enum CodingKeys: String, CodingKey {
        case name, email, type, size
    }
    
    // 自定义初始化处理可选值与默认值
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        email = try container.decodeIfPresent(String.self, forKey: .email) ?? ""
        name = try container.decodeIfPresent(String.self, forKey: .name) ?? "Guest"
        size = try container.decodeIfPresent(CoffeeSize.self, forKey: .size) ?? .small
        type = try container.decodeIfPresent(CoffeeType.self, forKey: .type) ?? .lattee
    }
}

struct Resource<T: Codable> {
    let url: URL
    var httpMethod: HTTPMethod = .get
}

2. 简化Alamofire解析代码

使用Alamofire原生的responseCodable方法直接解析,避免手动转换的错误:

func load<T>(resource: Resource<T>, completion: @escaping (Result<T, Error>) -> Void) {
    AF.request(resource.url, method: resource.httpMethod)
        .validate() // 验证HTTP状态码合法性
        .responseCodable(decoder: JSONDecoder()) { (response: DataResponse<T, AFError>) in
            switch response.result {
            case .success(let data):
                print(data)
                completion(.success(data))
            case .failure(let error):
                print(error.localizedDescription)
                completion(.failure(error))
            }
        }
}

3. 调用示例

调用时指定泛型为[Order].self,匹配API返回的数组结构:

guard let myurl = URL(string: "你的API地址") else { return }
let resource = Resource<[Order]>(url: myurl)
load(resource: resource) { result in
    switch result {
    case .success(let orders):
        // 处理获取到的订单数组
        for order in orders {
            print("姓名:\(order.name),邮箱:\(order.email),咖啡类型:\(order.type.rawValue),尺寸:\(order.size.rawValue)")
        }
    case .failure(let error):
        // 处理错误
        print("解析失败:\(error)")
    }
}

关键要点总结

  • 模型结构必须与API返回的JSON结构完全匹配:数组对应[Model],对象对应单个Model
  • CodingKeys的键名需与JSON中的键完全一致(大小写敏感)
  • 枚举的rawValue要和JSON中的字符串值完全匹配,无需多余的CodingKeys除非需要映射不同键名
  • 优先使用Alamofire的responseCodable方法,简化流程减少错误
  • 避免使用隐式解包可选类型(!),改用默认值或普通可选类型保证代码安全

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:16:03