Ответ
MVVM (Model-View-ViewModel) в iOS применяется со следующими технологическими стеками, обеспечивающими реактивную связь между ViewModel и View:
- SwiftUI — нативный, предпочтительный выбор. Встроенные property wrappers (
@StateObject,@ObservedObject,@Published) напрямую реализуют реактивные обновления. - UIKit + Combine — стандартный стек для реактивного программирования в UIKit. ViewModel реализует
ObservableObject, а View подписывается на его@Publishedсвойства. - UIKit + RxSwift/ReactiveSwift — альтернативы Combine, часто встречаются в legacy-проектах.
Почему важен реактивный стек? ViewModel не должна напрямую ссылаться на View. Вместо этого View подписывается на изменения состояния ViewModel, что обеспечивает слабую связность и упрощает тестирование.
Пример с UIKit и Combine:
// ViewModel
class UserListViewModel: ObservableObject {
@Published var users: [User] = []
private var cancellables = Set<AnyCancellable>()
func loadUsers() {
NetworkService.fetchUsers()
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in },
receiveValue: { [weak self] users in
self?.users = users
})
.store(in: &cancellables)
}
}
// View (UIViewController)
class UserListViewController: UIViewController {
private let viewModel = UserListViewModel()
private var cancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
setupBindings()
viewModel.loadUsers()
}
private func setupBindings() {
viewModel.$users
.receive(on: DispatchQueue.main)
.sink { [weak self] users in
self?.tableView.reloadData()
}
.store(in: &cancellables)
}
}