Какая ответственность у ViewModel?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Ответственность ViewModel в архитектуре MVVM
ViewModel (Модель-Представления) — это ключевой компонент архитектуры Model-View-ViewModel (MVVM), который выступает в качестве посредника между View (Пользовательский Интерфейс) и Model (Бизнес-логика/Данные). Его основная цель — отделить логику представления от пользовательского интерфейса, что делает код более тестируемым, поддерживаемым и удобным для разработки.
Основные обязанности ViewModel:
1. Предоставление данных для View
ViewModel подготавливает данные из Model в формате, удобном для отображения в View. Он может форматировать, фильтровать, агрегировать или преобразовывать сырые данные.
class UserProfileViewModel {
@Published var userName: String = ""
@Published var formattedJoinDate: String = ""
private let user: User
init(user: User) {
self.user = user
configureDisplayData()
}
private func configureDisplayData() {
userName = "\(user.firstName) \(user.lastName)"
let formatter = DateFormatter()
formatter.dateStyle = .medium
formattedJoinDate = "Joined: \(formatter.string(from: user.joinDate))"
}
}
2. Обработка пользовательского ввода
ViewModel обрабатывает действия пользователя (тапы, жесты, ввод текста) и преобразует их в команды для Model или изменения состояния.
class LoginViewModel {
@Published var email: String = ""
@Published var password: String = ""
@Published var isLoading: Bool = false
@Published var errorMessage: String?
private let authService: AuthenticationService
func login() {
isLoading = true
authService.login(email: email, password: password) { [weak self] result in
self?.isLoading = false
switch result {
case .success:
// Обработка успешного входа
case .failure(let error):
self?.errorMessage = error.localizedDescription
}
}
}
}
3. Управление состоянием View
ViewModel содержит и управляет состоянием, связанным с отображением данных:
- Состояние загрузки (loading, success, error)
- Видимость элементов интерфейса
- Текст и значения элементов управления
- Навигационные флаги
4. Реактивное программирование и привязка данных
В iOS ViewModel часто использует механизмы реактивного программирования для автоматического обновления View при изменении данных:
import Combine
class ShoppingCartViewModel: ObservableObject {
@Published var items: [CartItem] = []
@Published var totalPrice: Double = 0
private var cancellables = Set<AnyCancellable>()
init() {
$items
.map { items in
items.reduce(0) { $0 + $1.price * Double($1.quantity) }
}
.assign(to: \.totalPrice, on: self)
.store(in: &cancellables)
}
func addItem(_ item: CartItem) {
items.append(item)
}
}
5. Координация бизнес-логики
ViewModel координирует взаимодействие между различными сервисами и репозиториями, не содержа при этом самой сложной бизнес-логики:
class WeatherViewModel {
private let locationService: LocationService
private let weatherService: WeatherService
private let settingsRepository: SettingsRepository
@Published var currentWeather: WeatherData?
@Published var temperatureUnit: TemperatureUnit = .celsius
init(locationService: LocationService,
weatherService: WeatherService,
settingsRepository: SettingsRepository) {
self.locationService = locationService
self.weatherService = weatherService
self.settingsRepository = settingsRepository
loadSettings()
fetchWeather()
}
private func loadSettings() {
temperatureUnit = settingsRepository.getTemperatureUnit()
}
}
6. Подготовка данных для навигации
ViewModel может подготавливать данные, необходимые для перехода к другим экранам:
class ProductListViewModel {
@Published var products: [Product] = []
func productDetailsViewModel(for productId: String) -> ProductDetailsViewModel? {
guard let product = products.first(where: { $0.id == productId }) else {
return nil
}
return ProductDetailsViewModel(product: product)
}
}
Что ViewModel НЕ должен делать:
- Прямая работа с UI элементами — ViewModel не должен содержать ссылки на UIView/UIViewController
- Манипуляции с DOM/UIKit элементами — это ответственность View
- Сложная бизнес-логика — она должна находиться в Model или отдельных сервисах
- Прямой доступ к базе данных или сети — доступ через репозитории/сервисы
- Хранение тяжелых объектов — во избежание утечек памяти
Преимущества правильного использования ViewModel:
- Тестируемость: ViewModel можно тестировать без UI
- Переиспользование: одну ViewModel можно использовать с разными View
- Инкапсуляция: логика представления изолирована от UI кода
- Поддержка жизненного цикла: правильная обработка конфигурационных изменений на iOS
- Отсоединение зависимостей: View не зависит от конкретной реализации Model
Правильное разделение ответственности между View, ViewModel и Model — ключ к созданию масштабируемых и поддерживаемых iOS-приложений, особенно при работе с SwiftUI или комбинировании с реактивными подходами.