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

Swift异步/抛出错误处理问题:自定义错误无法正确捕获

解决Swift自定义错误无法正确捕获的问题

1. 先检查自定义错误枚举的定义与转换逻辑

确保你的EnemyAPIError枚举覆盖了目标错误场景,并且能正确关联系统错误。示例写法:

enum EnemyAPIError: Error, LocalizedError {
    case invalidURL
    case networkIssue(Error)
    case dataDecodingFailed
    
    var errorDescription: String? {
        switch self {
        case .invalidURL:
            return "无效的请求链接"
        case .networkIssue(let error):
            return error.localizedDescription
        case .dataDecodingFailed:
            return "数据解析失败"
        }
    }
}

2. 在DataService的getEnemy函数中正确抛出自定义错误

你遇到的核心问题大概率是:系统错误直接向上抛出,没有被转换为自定义错误。比如创建URL失败时,要立刻抛出invalidURL,而不是继续执行请求触发系统的“找不到主机”错误。正确写法参考:

class DataService {
    func getEnemy() async throws -> Enemy {
        // 先判断URL有效性,直接抛出自定义错误
        guard let url = URL(string: "你的请求地址") else {
            throw EnemyAPIError.invalidURL
        }
        
        do {
            let (data, response) = try await URLSession.shared.data(from: url)
            
            // 额外检查响应状态码,非200也可以转为自定义错误
            guard let httpResp = response as? HTTPURLResponse, httpResp.statusCode == 200 else {
                throw EnemyAPIError.networkIssue(NSError(domain: "API", code: -1, userInfo: [NSLocalizedDescriptionKey: "请求状态异常"]))
            }
            
            let enemy = try JSONDecoder().decode(Enemy.self, from: data)
            return enemy
        } catch {
            // 捕获系统错误,按类型转换为自定义错误
            if let urlError = error as? URLError {
                // 把找不到主机这类URL相关错误,映射到自定义的invalidURL
                if urlError.code == .cannotFindHost || urlError.code == .badURL {
                    throw EnemyAPIError.invalidURL
                } else {
                    throw EnemyAPIError.networkIssue(urlError)
                }
            } else if error is DecodingError {
                throw EnemyAPIError.dataDecodingFailed
            } else {
                throw EnemyAPIError.networkIssue(error)
            }
        }
    }
}

3. ViewModel中错误捕获的顺序要正确

必须先捕获自定义的EnemyAPIError,再用通用catch处理未知错误,否则通用分支会先拦截所有错误。示例:

class EnemyViewModel: ObservableObject {
    @Published var enemy: Enemy?
    @Published var errorMsg: String?
    
    func fetchEnemyAsync() async {
        do {
            let enemy = try await DataService().getEnemy()
            DispatchQueue.main.async {
                self.enemy = enemy
                self.errorMsg = nil
            }
        } catch let apiError as EnemyAPIError {
            DispatchQueue.main.async {
                self.errorMsg = apiError.localizedDescription
                // 针对不同自定义错误做针对性处理
                switch apiError {
                case .invalidURL:
                    print("DEBUG: 触发无效URL错误")
                case .networkIssue(let err):
                    print("DEBUG: 网络错误: \(err.localizedDescription)")
                case .dataDecodingFailed:
                    print("DEBUG: 数据解析失败")
                }
            }
        } catch {
            // 这里才处理真正的未知错误
            DispatchQueue.main.async {
                self.errorMsg = "未知错误"
                print("DEBUG: Unknown error occurred: \(error.localizedDescription)")
            }
        }
    }
}

快速排查清单

  • 确认getEnemy中创建URL失败时,是否立刻抛出了invalidURL,而不是继续执行请求
  • 检查系统错误捕获分支,是否把URLError的对应code(比如找不到主机)映射到了自定义错误
  • 确保ViewModel中先捕获EnemyAPIError,再处理通用错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 17:42:14