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

Swift中如何用单个Model适配两种不同格式的API响应?

解决API返回格式不统一的解析问题

核心问题是API返回格式不一致:不传withID时返回包含userInfo数组的对象,传入withID时返回单个ResultItem对象。要统一解析成[ResultItem],推荐两种解决方式:

方法一:自定义Model的解码逻辑(推荐)

通过给Results结构体实现自定义Codable解码逻辑,让它自动适配两种返回格式,同时修正ResultItem的编码忽略问题:

修改后的Model代码

struct ResultItem: Codable, Identifiable {
    let id = UUID()
    let userId: String
    var userlastname: String
    var username: String
    
    // 忽略API不返回的id字段
    enum CodingKeys: String, CodingKey {
        case userId, userlastname, username
    }
}

struct Results: Codable {
    let userInfo: [ResultItem]
    
    // 自定义解码逻辑,适配两种返回格式
    init(from decoder: Decoder) throws {
        do {
            // 先尝试解析无ID请求的格式:带userInfo数组的对象
            let keyedContainer = try decoder.container(keyedBy: CodingKeys.self)
            userInfo = try keyedContainer.decode([ResultItem].self, forKey: .userInfo)
        } catch {
            // 解析失败则尝试解析单个ResultItem,包装成数组
            let singleItem = try ResultItem(from: decoder)
            userInfo = [singleItem]
        }
    }
    
    enum CodingKeys: String, CodingKey {
        case userInfo
    }
    
    // 可选:实现编码逻辑以满足Codable协议完整要求
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(userInfo, forKey: .userInfo)
    }
}

修改后,原请求函数getUsers里的解码代码完全不用改动,就能自动处理两种返回情况,最终都能得到[ResultItem]数组。

方法二:在网络回调中手动判断处理

如果不想修改Model,可以在拿到返回数据后手动判断JSON类型,再分别解析:

修改后的请求回调代码

URLSession.shared.dataTask(with: urlHeader) { [self] (data, response , error) in
    guard let data = data else { 
        completion(.failure(.missingData)) // 需补充对应NetworkError枚举case
        return 
    }
    print(String(data: data, encoding: .utf8) ?? "Invalid JSON")

    do {
        let json = try JSONSerialization.jsonObject(with: data, options: [])
        if let _ = json as? [String: Any], let singleItem = try? JSONDecoder().decode(ResultItem.self, from: data) {
            // 处理单个ResultItem的情况
            completion(.success([singleItem]))
        } else if let results = try? JSONDecoder().decode(Results.self, from: data) {
            // 处理带userInfo数组的情况
            completion(.success(results.userInfo))
        } else {
            throw NetworkError.invalidResponse
        }
    } catch {
        print("Error:\(error)")
        completion(.failure(error as? NetworkError ?? .unknown))
    }
}.resume()

这种方式无需改动Model,但代码可读性和扩展性不如第一种方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:12:49