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
  • 第二部分:MVUI 在 SwiftUI 中的实现

第二部分:MVUI 在 SwiftUI 中的实现

第6章:MVVM 的数据流

案例:Todo 应用的完整数据流

1. 案例概述

在本案例中,我们将实现一个完整的 Todo 应用数据流,涵盖以下功能:

  • 显示待办事项列表
  • 添加新待办事项
  • 标记事项完成状态
  • 删除事项

通过此案例,您将理解 MVVM 中数据如何从 Model 层流向 View 层,以及用户交互如何通过 ViewModel 更新 Model。

2. 数据流实现步骤

2.1 Model 层设计
struct TodoItem: Identifiable, Codable {
    let id: UUID
    var title: String
    var isCompleted: Bool
    var createdAt: Date
}
2.2 ViewModel 实现
class TodoViewModel: ObservableObject {
    @Published var todos: [TodoItem] = []
    
    func addTodo(title: String) {
        let newTodo = TodoItem(
            id: UUID(),
            title: title,
            isCompleted: false,
            createdAt: Date()
        )
        todos.append(newTodo)
    }
    
    func toggleCompletion(for todo: TodoItem) {
        if let index = todos.firstIndex(where: { $0.id == todo.id }) {
            todos[index].isCompleted.toggle()
        }
    }
    
    func deleteTodo(at indexSet: IndexSet) {
        todos.remove(atOffsets: indexSet)
    }
}
2.3 View 层实现
struct TodoListView: View {
    @StateObject var viewModel = TodoViewModel()
    @State private var newTodoTitle = ""
    
    var body: some View {
        NavigationView {
            VStack {
                // 输入新待办事项
                HStack {
                    TextField("新增待办事项", text: $newTodoTitle)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                    
                    Button(action: {
                        guard !newTodoTitle.isEmpty else { return }
                        viewModel.addTodo(title: newTodoTitle)
                        newTodoTitle = ""
                    }) {
                        Image(systemName: "plus.circle.fill")
                    }
                }
                .padding()
                
                // 待办事项列表
                List {
                    ForEach(viewModel.todos) { todo in
                        HStack {
                            Image(systemName: todo.isCompleted ? "checkmark.circle.fill" : "circle")
                                .foregroundColor(todo.isCompleted ? .green : .gray)
                                .onTapGesture {
                                    viewModel.toggleCompletion(for: todo)
                                }
                            
                            Text(todo.title)
                                .strikethrough(todo.isCompleted)
                            
                            Spacer()
                            
                            Text(todo.createdAt, style: .time)
                                .font(.caption)
                                .foregroundColor(.gray)
                        }
                    }
                    .onDelete(perform: viewModel.deleteTodo)
                }
            }
            .navigationTitle("待办事项")
        }
    }
}

3. 数据流分析

  1. 初始化流程:

    • View 创建时实例化 TodoViewModel (@StateObject)
    • ViewModel 初始化 @Published 的 todos 数组
  2. 用户添加事项:

    • 用户在 TextField 输入文本 → 更新 newTodoTitle (@State)
    • 点击添加按钮 → 调用 ViewModel 的 addTodo 方法
    • ViewModel 更新 todos 数组 → 触发 View 自动更新
  3. 状态切换流程:

    • 用户点击完成状态图标 → 调用 ViewModel 的 toggleCompletion
    • ViewModel 修改对应 TodoItem 的 isCompleted 属性
    • @Published 属性变更触发 View 重绘
  4. 删除流程:

    • 用户滑动删除 → 调用 ViewModel 的 deleteTodo
    • ViewModel 更新数据 → View 同步更新 UI

4. 关键点说明

  • 单向数据流:所有数据修改都通过 ViewModel 进行,View 不直接修改 Model
  • 自动绑定:@Published 属性与 View 的自动绑定关系
  • 状态管理:使用 @StateObject 确保 ViewModel 生命周期与 View 一致

5. 完整项目结构建议

TodoApp/
├── Models/
│   └── TodoItem.swift
├── ViewModels/
│   └── TodoViewModel.swift
├── Views/
│   ├── TodoListView.swift
│   └── TodoItemView.swift
└── Utilities/
    └── TodoDataStore.swift

6. 扩展思考

  • 如何添加数据持久化功能?
  • 如何实现分类过滤功能?
  • 如何添加事项优先级功能?

通过这个案例,您已经掌握了 MVVM 在 SwiftUI 中的完整数据流实现方式。接下来可以尝试扩展更多功能来巩固理解。

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