Skip to Content

MVVM Pattern

1. Overview

View ←→ ViewModel ←→ Model UI Logic Data

2. Model

struct User: Identifiable, Codable { let id: Int let name: String let email: String }

3. ViewModel

@MainActor class UserListViewModel: ObservableObject { @Published var users: [User] = [] @Published var isLoading = false @Published var error: String? private let service: UserService init(service: UserService = UserService()) { self.service = service } func loadUsers() async { isLoading = true error = nil do { users = try await service.fetchUsers() } catch { self.error = error.localizedDescription } isLoading = false } func deleteUser(_ user: User) async { do { try await service.delete(user) users.removeAll { $0.id == user.id } } catch { self.error = error.localizedDescription } } }

4. View

struct UserListView: View { @StateObject var viewModel = UserListViewModel() var body: some View { Group { if viewModel.isLoading { ProgressView() } else if let error = viewModel.error { Text(error).foregroundColor(.red) } else { List(viewModel.users) { user in UserRow(user: user) } } } .task { await viewModel.loadUsers() } } }

5. Benefits

  • Testable: ViewModel có thể test riêng
  • Reusable: Logic tách khỏi UI
  • Maintainable: Clear separation

📝 Best Practices

  • ViewModel là @MainActor cho UI updates
  • Dùng @StateObject khi tạo ViewModel
  • Dùng @ObservedObject khi nhận từ parent
Last updated on