Как происходит передача данных между модулями в Clean Swift?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как происходит передача данных между компонентами Clean Swift (VIP-цикл)
В Clean Swift (VIP-архитектура) передача данных между модулями организована через формализованные Request-Response-View Models и односторонний VIP-цикл, что обеспечивает полное разделение ответственности и тестируемость. Основной механизм — это последовательная передача структур данных между четырьмя ключевыми компонентами: View Controller, Interactor, Presenter и Router.
1. Основной поток данных (VIP-цикл)
Данные передаются по цепочке View Controller → Interactor → Presenter → View Controller:
🔄 Типичный сценарий (например, загрузка списка пользователей):
// 1. View Controller отправляет Request в Interactor
class UsersViewController: UIViewController {
func viewDidLoad() {
super.viewDidLoad()
let request = UsersList.Request()
interactor?.fetchUsers(request: request)
}
}
// 2. Interceptor обрабатывает бизнес-логику и передает Response в Presenter
class UsersInteractor: UsersBusinessLogic {
func fetchUsers(request: UsersList.Request) {
// Бизнес-логика, работа с сервисами
let users = networkService.loadUsers()
let response = UsersList.Response(users: users)
presenter?.presentUsers(response: response)
}
}
// 3. Presenter форматирует данные для отображения и создает View Model
class UsersPresenter: UsersPresentationLogic {
func presentUsers(response: UsersList.Response) {
let viewModel = UsersList.ViewModel(
displayedUsers: response.users.map {
UserDisplayItem(name: $0.name, email: $0.email)
}
)
viewController?.displayUsers(viewModel: viewModel)
}
}
// 4. View Controller получает готовую View Model и обновляет UI
class UsersViewController: UIViewController, UsersDisplayLogic {
func displayUsers(viewModel: UsersList.ViewModel) {
// Обновление таблицы/коллекции
self.displayedUsers = viewModel.displayedUsers
tableView.reloadData()
}
}
2. Ключевые структуры данных для передачи
Для каждого use case создаются отдельные структуры, обычно объединенные во вложенные enum или struct:
enum UsersList {
// Request от View Controller к Interactor (обычно пустая, но может содержать параметры)
struct Request { }
// Response от Interactor к Presenter (сырые данные)
struct Response {
let users: [User]
let error: Error?
}
// View Model от Presenter к View Controller (отформатированные для отображения данные)
struct ViewModel {
struct DisplayedUser {
let name: String
let email: String
let formattedJoinDate: String
}
let displayedUsers: [DisplayedUser]
let errorMessage: String?
}
}
3. Передача данных между модулями (Router)
Для навигации между разными VIP-стеками используется Router, который получает данные от Interactor:
// В Interactor (подготовка данных для передачи)
func showUserDetails(request: UserDetails.Request) {
let user = currentUser
let dataToPass = UserDetails.DataPassing(user: user)
router?.routeToUserDetails(data: dataToPass)
}
// В Router (передача данных следующему модулю)
func routeToUserDetails(data: UserDetails.DataPassing) {
// 1. Создание следующего VIP-стека
let destinationVC = UserDetailsViewController()
let destinationInteractor = destinationVC.interactor!
// 2. Передача данных через DataStore протокол
destinationInteractor.user = data.user
// 3. Навигация
viewController?.navigationController?.pushViewController(destinationVC, animated: true)
}
4. Протоколы как контракты передачи данных
Каждый компонент объявляет протоколы для входных/выходных данных:
protocol UsersBusinessLogic {
func fetchUsers(request: UsersList.Request)
}
protocol UsersPresentationLogic {
func presentUsers(response: UsersList.Response)
}
protocol UsersDisplayLogic {
func displayUsers(viewModel: UsersList.ViewModel)
}
protocol UsersDataStore {
var selectedUser: User? { get set }
}
5. Особенности передачи данных в Clean Swift
- Односторонний поток: данные движутся только в одном направлении, что упрощает отладку
- Иммутабельность: Request/Response/View Model — это value types (struct), предотвращающие побочные эффекты
- Инкапсуляция формата данных: View Controller не знает о структуре доменных объектов
- Явные зависимости: все зависимости инжектятся через инициализаторы, что облегчает тестирование
- Разделение преобразования данных:
- Interactor работает с "сырыми" данными (моделями, Core Data, сетью)
- Presenter занимается форматированием (даты, валюты, локализация)
6. Преимущества такого подхода
- Тестируемость: каждый компонент тестируется изолированно с mock-объектами
- Поддержка: изменения в UI не затрагивают бизнес-логику и наоборот
- Повторное использование: Interactor и Presenter не зависят от UIKit
- Читаемость: каждый компонент имеет одну четкую ответственность
- Безопасность типов: компилятор проверяет соответствие структур данных между компонентами
Clean Swift обеспечивает детерминированную, предсказуемую передачу данных через формальные контракты, что особенно важно в больших проектах с множеством разработчиков и сложной бизнес-логикой.