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

SwiftUI(MVVM模式)下错误处理的最佳实践探讨

SwiftUI 错误处理最佳实践

一、错误分层处理的核心原则

  • 底层组件(如NetworkManager、辅助类)应抛出具体的领域相关错误,而非笼统的系统错误,让上层能精准定位问题类型。
  • 业务相关的错误处理逻辑优先放在ViewModel层完成,View层仅负责展示错误状态,不介入业务逻辑处理。

二、ViewModel 与 View 的错误职责划分

  • 推荐方案:ViewModel捕获处理错误,通过@Published传递状态给View
    ViewModel作为数据与业务逻辑的中间层,负责调用底层服务、捕获错误,再将错误转化为View可直接使用的状态(比如@Published var errorState: ErrorState?或@Published var errorMessage: String?)。View只需根据状态展示对应提示(如Alert、Toast),无需关心错误根源与处理逻辑。
  • 不建议在View层处理错误逻辑
    View层的核心职责是UI渲染与用户交互,把错误处理放在这里会导致UI代码臃肿,违反单一职责原则,还会让状态管理变得混乱,难以维护。
  • 单纯向上重抛属于不良实践
    若只是把错误逐层上抛却不做处理或转化,上层拿到的错误会零散杂乱,既无法给用户提供友好反馈,也不利于问题排查。

三、自定义错误的设计策略

  • 优先按模块定义细分错误
    比如定义NetworkManagerError(包含网络超时、请求失败、解析错误等)、HelperClassError(包含参数无效、数据格式错误等),每个模块的错误职责清晰,便于定位问题。
  • 可选全局统一错误类型
    若需要在ViewModel层统一处理所有错误,可定义AppError枚举,将各模块错误作为关联值包含,示例如下:
    enum AppError: Error, LocalizedError {
        case network(NetworkManagerError)
        case helper(HelperClassError)
        case unknown(Error)
        
        var errorDescription: String? {
            switch self {
            case .network(let error): return error.localizedDescription
            case .helper(let error): return error.localizedDescription
            case .unknown(let error): return error.localizedDescription
            }
        }
    }
    
    这样ViewModel可将所有底层错误转化为AppError,统一处理后再传递给View,降低上层判断复杂度。
  • 给自定义错误实现LocalizedError协议
    直接返回用户友好的错误提示文本,无需在View层额外做字符串映射。

四、实际代码示例

底层NetworkManager的自定义错误

enum NetworkManagerError: Error, LocalizedError {
    case requestTimeout
    case invalidResponse
    case dataParsingFailed
    
    var errorDescription: String? {
        switch self {
        case .requestTimeout: return "请求超时,请稍后重试"
        case .invalidResponse: return "服务器返回无效数据"
        case .dataParsingFailed: return "数据解析失败"
        }
    }
}

class NetworkManager {
    func fetchData() throws -> Data {
        // 模拟网络请求失败
        throw NetworkManagerError.requestTimeout
    }
}

ViewModel处理错误并传递状态

class ContentViewModel: ObservableObject {
    @Published var data: Data?
    @Published var error: AppError?
    
    private let networkManager = NetworkManager()
    
    func loadData() {
        do {
            let result = try networkManager.fetchData()
            data = result
            error = nil
        } catch let networkError as NetworkManagerError {
            error = .network(networkError)
        } catch {
            error = .unknown(error)
        }
    }
}

View层展示错误

struct ContentView: View {
    @StateObject private var viewModel = ContentViewModel()
    
    var body: some View {
        Button("加载数据") {
            viewModel.loadData()
        }
        .alert(item: $viewModel.error) { error in
            Alert(title: Text("出错了"), message: Text(error.errorDescription ?? "未知错误"), dismissButton: .default(Text("确定")))
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:13:32