第四部分:实践与案例
第10章:完整项目开发
实现一个完整的 MVVM 项目(例如:个人财务管理应用)
1. 项目概述
我们将开发一个个人财务管理应用,核心功能包括:
- 收支记录增删改查
- 按类别/时间统计报表
- 预算设置与超支预警
- 数据本地持久化(支持iCloud同步)
2. 架构设计
graph TD
A[View] -->|绑定| B(ViewModel)
B -->|读写| C[Model]
C -->|通知| B
B -->|驱动| A
3. 分层实现
Model 层设计
// 核心数据模型
struct Transaction: Identifiable, Codable {
let id: UUID
var amount: Double
var category: Category
var date: Date
var notes: String
}
enum TransactionType: String, CaseIterable {
case income, expense
}
// 持久化服务协议
protocol DataServiceProtocol {
func save(_ transaction: Transaction) async throws
func fetchAll() async throws -> [Transaction]
}
ViewModel 层实现
@MainActor
final class FinanceViewModel: ObservableObject {
@Published private(set) var transactions: [Transaction] = []
@Published var currentMonthTotal: Double = 0
private let dataService: DataServiceProtocol
init(dataService: DataServiceProtocol) {
self.dataService = dataService
}
func addTransaction(_ transaction: Transaction) async {
do {
try await dataService.save(transaction)
try await loadTransactions()
calculateTotals()
} catch {
// 错误处理
}
}
private func loadTransactions() async throws {
transactions = try await dataService.fetchAll()
}
}
View 层关键组件
struct TransactionListView: View {
@StateObject var viewModel: FinanceViewModel
var body: some View {
List {
Section("本月汇总") {
AmountSummaryView(total: viewModel.currentMonthTotal)
}
ForEach(viewModel.transactions) { transaction in
TransactionRow(transaction: transaction)
}
.onDelete(perform: deleteTransactions)
}
.task { await viewModel.loadTransactions() }
}
private func deleteTransactions(at offsets: IndexSet) {
// 删除逻辑实现
}
}
4. 关键技术实现
数据绑定示例
// 预算进度条组件
struct BudgetProgressView: View {
@Binding var currentSpending: Double
var budgetLimit: Double
var body: some View {
VStack {
ProgressView(value: currentSpending, total: budgetLimit)
Text("\(currentSpending.formatted(.currency(code: "CNY"))) / \(budgetLimit.formatted(.currency(code: "CNY")))")
}
}
}
跨组件通信
// 使用EnvironmentObject传递根ViewModel
@main
struct FinanceApp: App {
@StateObject private var rootVM = AppRootViewModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(rootVM)
}
}
}
5. 项目结构组织
FinanceApp/
├── Models/
│ ├── Transaction.swift
│ └── Category.swift
├── Services/
│ ├── DataService.swift
│ └── CloudKitService.swift
├── ViewModels/
│ ├── FinanceViewModel.swift
│ └── ReportViewModel.swift
├── Views/
│ ├── Transaction/
│ └── Dashboard/
└── Utilities/
├── Extensions/
└── Formatters/
6. 典型问题解决方案
问题1:列表性能优化
// 使用LazyVStack替代List
ScrollView {
LazyVStack(pinnedViews: .sectionHeaders) {
ForEach(viewModel.transactions) { transaction in
TransactionRow(transaction: transaction)
.transactionListItemStyle() // 自定义样式修饰符
}
}
}
问题2:ViewModel 生命周期管理
// 使用@StateObject确保单例
struct CategoryView: View {
@StateObject var viewModel = CategoryViewModel()
var body: some View {
// ...
}
}
7. 完整功能流程图
sequenceDiagram
participant User
participant View
participant ViewModel
participant Model
User->>View: 点击"添加支出"
View->>ViewModel: addTransaction()
ViewModel->>Model: save(data)
Model-->>ViewModel: 保存结果
ViewModel->>ViewModel: 重新计算统计
ViewModel-->>View: 更新@Published属性
View->>View: 自动刷新UI
8. 扩展思考
- 如何添加多设备同步功能?
- 实现导出PDF报表的方案
- 接入银行API自动导入交易记录
