viewModel + Repo + SwiftData 最佳实践示例

你可以使用 ViewModelRepository 模式来统一管理 SwiftData 数据。这种模式有助于分离数据逻辑与视图逻辑,使代码更加模块化和可维护。

1. 定义 Repository 类

Repository 类负责与 SwiftData 交互,处理数据的增删改查操作。它封装了数据访问逻辑,可以被多个 ViewModel 重用。

import SwiftData

class TodoRepository {
    private let modelContext: ModelContext

    init(modelContext: ModelContext) {
        self.modelContext = modelContext
    }

    // Fetch all todos for a specific user
    func fetchTodos(for user: User) -> [TodoItem] {
        let fetchRequest = FetchRequest<TodoItem>(predicate: #Predicate { $0.user == user })
        return (try? modelContext.fetch(fetchRequest)) ?? []
    }

    // Add a new todo
    func addTodoItem(title: String, for user: User) {
        let newItem = TodoItem(title: title, user: user)
        modelContext.insert(newItem)
    }

    // Delete a todo item
    func deleteTodoItem(_ item: TodoItem) {
        modelContext.delete(item)
    }

    // Toggle completion of a todo item
    func toggleCompletion(for item: TodoItem) {
        item.isCompleted.toggle()
    }
}

2. 定义 ViewModel

ViewModel 使用 Repository 来管理数据,并将数据传递给视图。它充当视图和数据层之间的桥梁。

import SwiftUI

class TodoViewModel: ObservableObject {
    @Published var todos: [TodoItem] = []
    @Published var selectedUser: User?

    private let repository: TodoRepository

    init(repository: TodoRepository) {
        self.repository = repository
    }

    // Fetch todos for the selected user
    func fetchTodos() {
        if let user = selectedUser {
            todos = repository.fetchTodos(for: user)
        } else {
            todos = []
        }
    }

    // Add a new todo item
    func addTodoItem(title: String) {
        if let user = selectedUser {
            repository.addTodoItem(title: title, for: user)
            fetchTodos()
        }
    }

    // Delete a todo item
    func deleteTodoItem(at offsets: IndexSet) {
        for index in offsets {
            let item = todos[index]
            repository.deleteTodoItem(item)
        }
        fetchTodos()
    }

    // Toggle completion status
    func toggleCompletion(for item: TodoItem) {
        repository.toggleCompletion(for: item)
        fetchTodos()
    }

    // Set the selected user
    func selectUser(_ user: User) {
        selectedUser = user
        fetchTodos()
    }
}

3. 使用 ViewModel 和 Repository 在 SwiftUI 中

在视图中使用 ViewModel 来绑定数据,并响应用户的交互操作。

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @StateObject private var viewModel: TodoViewModel

    init() {
        // Initialize the repository and view model
        let repository = TodoRepository(modelContext: modelContext)
        _viewModel = StateObject(wrappedValue: TodoViewModel(repository: repository))
    }

    var body: some View {
        NavigationView {
            VStack {
                // User selection
                if let users = try? modelContext.fetch(User.all()) {
                    Picker("Select User", selection: $viewModel.selectedUser) {
                        ForEach(users, id: \.id) { user in
                            Text(user.name).tag(user as User?)
                        }
                    }
                    .pickerStyle(MenuPickerStyle())
                    .padding()
                }

                // Todo list
                List {
                    ForEach(viewModel.todos) { item in
                        HStack {
                            Text(item.title)
                            Spacer()
                            Button(action: {
                                viewModel.toggleCompletion(for: item)
                            }) {
                                Image(systemName: item.isCompleted ? "checkmark.circle.fill" : "circle")
                            }
                            .buttonStyle(PlainButtonStyle())
                        }
                    }
                    .onDelete(perform: viewModel.deleteTodoItem)
                }

                // Add new todo item
                HStack {
                    TextField("New todo", text: $newItemTitle)
                        .textFieldStyle(RoundedBorderTextFieldStyle())
                        .padding()
                    
                    Button(action: {
                        viewModel.addTodoItem(title: newItemTitle)
                        newItemTitle = ""
                    }) {
                        Image(systemName: "plus")
                            .padding()
                    }
                }
            }
            .navigationTitle("Todo List")
            .onAppear {
                viewModel.fetchTodos()
            }
        }
    }
}

4. 解释代码

  • TodoRepository: 封装了所有与 SwiftData 的交互逻辑。它负责管理 TodoItem 的 CRUD 操作。
  • TodoViewModel: 使用 TodoRepository 来执行数据操作,并将结果发布给视图。它负责管理视图状态,例如 todosselectedUser
  • ContentView: 使用 TodoViewModel 绑定 UI 和数据。ViewModel 的状态变化会自动反映在视图中。

5. 优点

  • 分离关注点: ViewModel 负责处理视图逻辑,Repository 负责处理数据逻辑。这使得代码更易于维护和测试。
  • 代码复用: 多个 ViewModel 可以共享相同的 Repository,避免重复数据访问逻辑。
  • 模块化: 可以独立测试 RepositoryViewModel,提高代码的可靠性。

这样,你可以更好地管理和组织 SwiftData 数据,特别是在复杂的应用程序中。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值