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

Swift服务类中如何将Error转换为自定义APICallError枚举?

如何将通用Error转换为自定义APICallError枚举

这是个很常见的需求——把通用Error类型转换成自定义的枚举,方便调用方更清晰地处理不同错误场景。下面我给你详细讲下实现思路和代码示例:

第一步:完善自定义错误枚举(可选但推荐)

首先,建议给你的APICallError添加一个unknown case,用来处理无法匹配的未知错误,这样能保留原始错误信息,避免丢失关键调试数据:

enum APICallError: Error {
    case insufficientCredentials
    case malformedResponse
    case forbidden
    case unknown(Error) // 包裹无法识别的原始错误
}

第二步:编写转换函数

在你的服务类里,添加一个私有转换函数,负责把任意Error实例映射到APICallError:

private func convertToAPICallError(_ error: Error) -> APICallError {
    // 1. 如果错误本身就是APICallError,直接返回
    if let apiError = error as? APICallError {
        return apiError
    }
    
    // 2. 处理常见的系统错误,比如URLError
    if let urlError = error as? URLError {
        switch urlError.code {
        case .userAuthenticationRequired, .userCancelledAuthentication:
            return .insufficientCredentials
        case .badServerResponse, .cannotParseResponse:
            return .malformedResponse
        case .forbidden:
            return .forbidden
        default:
            return .unknown(error)
        }
    }
    
    // 3. 可以添加其他自定义错误类型的处理逻辑
    // 比如如果你的后端返回了特定的业务错误码,也可以在这里解析映射
    
    // 4. 所有无法匹配的错误都归入unknown
    return .unknown(error)
}

第三步:在服务方法中应用转换

在你的makeCall方法里,无论哪里产生了Error,都用这个转换函数处理后再传给onError回调:

class APIService {
    typealias APIResponse = (Data) -> Void
    typealias APIError = (Error) -> Void
    
    func makeCall(onSuccess: @escaping APIResponse, onError: @escaping APIError) {
        // 模拟实际的后端调用(这里用URLSession示例)
        guard let url = URL(string: "https://your-api-endpoint.com") else {
            onError(APICallError.malformedResponse)
            return
        }
        
        URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
            guard let self = self else { return }
            
            // 处理请求阶段的错误
            if let error = error {
                let convertedError = self.convertToAPICallError(error)
                onError(convertedError)
                return
            }
            
            // 处理响应阶段的错误(比如HTTP状态码)
            guard let httpResponse = response as? HTTPURLResponse else {
                onError(APICallError.malformedResponse)
                return
            }
            
            switch httpResponse.statusCode {
            case 200...299:
                // 成功响应,传递数据
                guard let data = data else {
                    onError(APICallError.malformedResponse)
                    return
                }
                onSuccess(data)
            case 401:
                onError(APICallError.insufficientCredentials)
            case 403:
                onError(APICallError.forbidden)
            default:
                // 其他状态码包装成unknown错误
                let statusError = NSError(domain: "APIService", code: httpResponse.statusCode, userInfo: nil)
                onError(APICallError.unknown(statusError))
            }
        }.resume()
    }
    
    // 上面的转换函数放在这里
    private func convertToAPICallError(_ error: Error) -> APICallError {
        if let apiError = error as? APICallError {
            return apiError
        }
        
        if let urlError = error as? URLError {
            switch urlError.code {
            case .userAuthenticationRequired, .userCancelledAuthentication:
                return .insufficientCredentials
            case .badServerResponse, .cannotParseResponse:
                return .malformedResponse
            case .forbidden:
                return .forbidden
            default:
                return .unknown(error)
            }
        }
        
        return .unknown(error)
    }
}

调用方如何处理错误

当调用方使用你的服务时,可以轻松地通过switch语句处理不同的错误场景:

let apiService = APIService()
apiService.makeCall(onSuccess: { data in
    // 处理成功返回的数据
}) { error in
    guard let apiCallError = error as? APICallError else {
        print("无法识别的错误类型")
        return
    }
    
    switch apiCallError {
    case .insufficientCredentials:
        // 提示用户重新登录
        print("请重新登录以继续")
    case .malformedResponse:
        // 提示服务器响应异常
        print("服务器返回无效数据")
    case .forbidden:
        // 提示无权限
        print("你没有访问该资源的权限")
    case .unknown(let originalError):
        // 处理未知错误,可打印原始信息用于调试
        print("发生未知错误: \(originalError.localizedDescription)")
    }
}

关键要点总结

  • 优先匹配已知错误类型:先检查错误是否已经是APICallError,再处理系统或其他自定义错误。
  • 保留原始错误信息:用unknown(Error)包裹无法识别的错误,方便调试和后续扩展。
  • 覆盖全场景:不仅处理请求阶段的错误,还要处理响应阶段的HTTP状态码错误,确保所有错误都能被转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:57:06