Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 错误处理与用户反馈

错误处理与用户反馈

在 MVVM 架构中,优雅地处理错误并提供清晰的用户反馈是提升应用健壮性和用户体验的关键环节。本节将探讨如何在 SwiftUI 中实现这一目标。

错误处理的设计原则

1. 错误分类与建模

  • 领域错误(如业务逻辑失败)
  • 网络错误(如请求超时、服务器错误)
  • 本地错误(如数据验证失败、存储失败)
enum AppError: Error, LocalizedError {
    case networkError(description: String)
    case validationFailed(field: String)
    case persistenceError
    
    var errorDescription: String? {
        switch self {
        case .networkError(let desc):
            return "网络错误: \(desc)"
        case .validationFailed(let field):
            return "\(field) 验证失败"
        case .persistenceError:
            return "数据存储失败"
        }
    }
}

2. ViewModel 中的错误处理

class TodoViewModel: ObservableObject {
    @Published var error: AppError?
    
    func fetchTodos() {
        Task {
            do {
                let todos = try await apiService.fetchTodos()
                // 更新数据...
            } catch {
                DispatchQueue.main.async {
                    self.error = error as? AppError
                }
            }
        }
    }
}

用户反馈的实现方式

1. 使用 Alert 展示错误

struct TodoListView: View {
    @ObservedObject var viewModel: TodoViewModel
    
    var body: some View {
        List(viewModel.todos) { todo in
            // ...
        }
        .alert("错误", 
               isPresented: .constant(viewModel.error != nil),
               presenting: viewModel.error) { error in
            Button("确定", role: .cancel) {
                viewModel.error = nil
            }
        } message: { error in
            Text(error.localizedDescription)
        }
    }
}

2. 非侵入式 Toast 提示

// 在 ViewModel 中
@Published var toastMessage: String?

// 在视图中
.overlay(alignment: .bottom) {
    if let message = viewModel.toastMessage {
        Text(message)
            .padding()
            .background(Color.black.opacity(0.7))
            .foregroundColor(.white)
            .cornerRadius(10)
            .transition(.move(edge: .bottom))
            .onAppear {
                DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                    viewModel.toastMessage = nil
                }
            }
    }
}

3. 表单验证的即时反馈

struct TodoFormView: View {
    @ObservedObject var viewModel: TodoFormViewModel
    @State private var showValidationErrors = false
    
    var body: some View {
        Form {
            TextField("标题", text: $viewModel.title)
                .background(
                    viewModel.isTitleValid ? Color.clear : Color.red.opacity(0.1)
                )
            
            if showValidationErrors && !viewModel.isTitleValid {
                Text("标题不能为空")
                    .foregroundColor(.red)
            }
            
            // ...
            
            Button("保存") {
                if viewModel.validate() {
                    viewModel.save()
                } else {
                    showValidationErrors = true
                }
            }
        }
    }
}

最佳实践建议

  1. 错误本地化:为所有错误类型提供用户友好的本地化描述
  2. 错误恢复:尽可能提供恢复选项(如重试按钮)
  3. 日志记录:在显示用户反馈的同时记录详细错误日志
  4. 统一处理:创建全局错误处理器来集中管理常见错误
  5. 避免阻塞:长时间操作应提供进度指示

案例:Todo 应用的错误处理增强

// 增强后的 ViewModel
class EnhancedTodoViewModel: ObservableObject {
    enum State {
        case idle, loading, loaded([Todo]), failed(AppError)
    }
    
    @Published private(set) var state: State = .idle
    
    func loadTodos() {
        state = .loading
        Task {
            do {
                let todos = try await repository.fetchTodos()
                DispatchQueue.main.async {
                    self.state = .loaded(todos)
                }
            } catch {
                DispatchQueue.main.async {
                    self.state = .failed(error as? AppError ?? .networkError(description: "未知错误"))
                }
            }
        }
    }
}

// 对应的视图
struct EnhancedTodoView: View {
    @ObservedObject var viewModel: EnhancedTodoViewModel
    
    var body: some View {
        Group {
            switch viewModel.state {
            case .idle:
                ProgressView()
            case .loading:
                ProgressView("加载中...")
            case .loaded(let todos):
                TodoList(todos: todos)
            case .failed(let error):
                ErrorView(error: error, onRetry: viewModel.loadTodos)
            }
        }
        .onAppear {
            viewModel.loadTodos()
        }
    }
}

通过系统化的错误处理和用户反馈机制,可以显著提升应用的可靠性和用户体验,同时保持代码的可维护性。

Last Updated:: 4/25/25, 8:30 PM