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

如何利用泛型Response结构体解码通用响应中的数据?

泛型Response结构体解码数组数据的修正方案

问题梳理

你的代码存在几个关键问题导致无法正确解码:

  • Mock JSON存在语法错误(数组元素末尾多余逗号)
  • Pokemon遵循Identifiable但未实现id属性
  • loadData函数中类型不匹配(期望返回[Value],但解码时用Response<Value>,而实际data是数组类型)
  • 缺失request变量定义和NetworkError枚举

修正后的完整代码

// 修正JSON格式,移除多余逗号
let mockData = """
{
  "status": "ok",
  "data": [
    {
        "name": "Pikachu"
    },
    {
        "name": "Squirtle"
    },
    {
        "name": "Eevee"
    }
  ]
}
""".data(using: .utf8)!

// 泛型Response结构体保持不变
struct Response<T: Decodable>: Decodable {
    let status: String
    let data: T
}

// 补充NetworkError枚举定义
enum NetworkError: Error {
    case invalidPayLoad
    case invalidRequest
}

// EndPoint补充url属性,用于构建请求
public enum EndPoint: String {
    case characters = "your-api-url-here"
    
    var url: URL {
        URL(string: rawValue)! // 实际项目中建议处理可选绑定
    }
}

protocol APIManagerProtocol {
    func loadData<Value: Decodable>(endPoint: EndPoint) async throws -> [Value]
}

actor APIManager: APIManagerProtocol {
    static let shared = APIManager()

    private let session = URLSession.shared
    private let decoder = JSONDecoder()

    func loadData<Value: Decodable>(endPoint: EndPoint) async throws -> [Value] {
        // 构建请求
        let request = URLRequest(url: endPoint.url)
        
        // 实际请求数据(这里暂时用mockData代替,可注释掉换成下面的真实请求)
        let data = mockData
        // let (data, response) = try await session.data(for: request)
        
        // 解码为Response<[Value]>,因为data是数组类型
        let payload = try decoder.decode(Response<[Value]>.self, from: data)
        
        guard payload.status == "ok" else {
            throw NetworkError.invalidPayLoad
        }
        
        return payload.data
    }
}

// 修正Pokemon结构体,添加id属性(Identifiable要求)
struct Pokemon: Identifiable, Decodable {
    let id = UUID() // 自动生成UUID作为id
    let name: String
}

// 调用示例
func fetchPokemon() async {
    let api = APIManager.shared
    do {
        let pokemon = try await api.loadData(endPoint: .characters)
        print(pokemon)
    } catch {
        print(error)
    }
}

关键修改说明

  1. JSON修正:删除数组元素末尾的逗号,避免JSON解析失败。
  2. Pokemon结构体:添加id属性满足Identifiable协议要求,这里用UUID()自动生成,也可以根据业务逻辑用name作为id(需确保唯一)。
  3. loadData函数:
    • 补充request变量的构建,基于EndPoint的url属性生成请求。
    • 解码时指定Response<[Value]>.self,因为接口返回的data是数组类型,这样payload.data直接就是[Value],符合函数返回类型。
    • 使用成员变量decoder而不是每次创建新的JSONDecoder,更高效。
  4. 补充必要定义:添加NetworkError枚举和EndPoint的url属性,让代码完整可运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:55:20