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

如何从Endpoint结构体属性传递Decodable.Protocol作为函数参数?

非泛型Endpoint传递Decodable类型到Alamofire的问题

我定义了如下Endpoint结构体,用于封装API请求的核心信息:

struct Endpoint {
    let responseDecodable: Decodable.Type
    let path: String
    let queryItems: [URLQueryItem]
    
    // 假设此处包含URL构建的计算属性逻辑
    var url: URL? {
        return nil
    }
}

通过Alamofire发起请求的函数实现如下:

func fetchData(_ endpoint: Endpoint) {
    AF.request(endpoint.url!).responseDecodable(of: endpoint.responseDecodable) { response in
        // 响应处理逻辑
    }
}

为不同API接口定义了Endpoint的静态构造方法:

extension Endpoint {
    static func getUser(by id: Int) -> Endpoint {
        return Endpoint(
            responseDecodable: UsersGet.self,
            path: "/users/\(id)",
            queryItems: []
        )
    }
    
    static func getFriends(by user: User) -> Endpoint {
        return Endpoint(
            responseDecodable: FriendsGet.self,
            path: "/users/\(user.id)/friends",
            queryItems: []
        )
    }
}

当前遇到的问题:调用fetchData时触发报错 Cannot convert value of type 'Decodable.Type' to expected argument type 'T.Type',原因是Alamofire的responseDecodable(of:)要求传入具体的泛型类型,而非抽象的Decodable.Type。需要在不将Endpoint改为泛型结构体的前提下解决该类型传递问题。


解决方案

方案1:调整fetchData为泛型函数,调用时显式指定类型

修改fetchData为泛型函数,让调用者明确指定期望的解码类型,同时校验Endpoint存储的类型是否匹配:

func fetchData<T: Decodable>(_ endpoint: Endpoint, completion: @escaping (Result<T, Error>) -> Void) {
    // 校验类型一致性,避免类型不兼容问题
    guard endpoint.responseDecodable == T.self else {
        let mismatchError = NSError(
            domain: "APIError",
            code: 1001,
            userInfo: [NSLocalizedDescriptionKey: "Endpoint响应类型与期望类型不匹配"]
        )
        completion(.failure(mismatchError))
        return
    }
    
    AF.request(endpoint.url!)
        .responseDecodable(of: T.self) { response in
            completion(response.result)
        }
}

调用示例:

// 获取用户信息
fetchData(Endpoint.getUser(by: 1)) { (result: Result<UsersGet, Error>) in
    switch result {
    case .success(let user):
        // 处理UsersGet类型数据
        print(user)
    case .failure(let error):
        print(error.localizedDescription)
    }
}

// 获取好友列表
fetchData(Endpoint.getFriends(by: currentUser)) { (result: Result<FriendsGet, Error>) in
    switch result {
    case .success(let friends):
        // 处理FriendsGet类型数据
        print(friends)
    case .failure(let error):
        print(error.localizedDescription)
    }
}

方案2:将请求解码逻辑封装到Endpoint内部

给Endpoint扩展一个请求执行方法,直接处理请求和解码,回调返回Decodable类型,调用时再做类型转换:

extension Endpoint {
    func performRequest(completion: @escaping (Result<Decodable, Error>) -> Void) {
        guard let url = url else {
            let invalidURLError = NSError(
                domain: "APIError",
                code: 1000,
                userInfo: [NSLocalizedDescriptionKey: "无效的请求URL"]
            )
            completion(.failure(invalidURLError))
            return
        }
        
        AF.request(url)
            .responseData { response in
                switch response.result {
                case .success(let data):
                    do {
                        let decodedObject = try JSONDecoder().decode(self.responseDecodable, from: data)
                        completion(.success(decodedObject))
                    } catch {
                        completion(.failure(error))
                    }
                case .failure(let error):
                    completion(.failure(error))
                }
            }
    }
}

调用示例:

Endpoint.getUser(by: 1).performRequest { result in
    switch result {
    case .success(let object):
        if let user = object as? UsersGet {
            // 处理用户数据
            print(user)
        }
    case .failure(let error):
        print(error.localizedDescription)
    }
}

方案3:使用Alamofire底层的_responseDecodable方法

Alamofire提供了底层的_responseDecodable方法,可直接接受Decodable.Type参数,绕过泛型限制:

func fetchData(_ endpoint: Endpoint, completion: @escaping (Result<Decodable, Error>) -> Void) {
    guard let url = endpoint.url else {
        let invalidURLError = NSError(
            domain: "APIError",
            code: 1000,
            userInfo: [NSLocalizedDescriptionKey: "无效的请求URL"]
        )
        completion(.failure(invalidURLError))
        return
    }
    
    AF.request(url)
        ._responseDecodable(decoder: JSONDecoder(), responseSerializer: DecodableResponseSerializer(type: endpoint.responseDecodable)) { response in
            completion(response.result)
        }
}

调用时需在回调中做类型转换,逻辑同方案2。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 10:35:22