← Назад к вопросам

Как происходит передача данных между модулями в Clean Swift?

2.0 Middle🔥 111 комментариев
#Архитектура и паттерны#Язык Swift

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как происходит передача данных между компонентами 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. Преимущества такого подхода

  1. Тестируемость: каждый компонент тестируется изолированно с mock-объектами
  2. Поддержка: изменения в UI не затрагивают бизнес-логику и наоборот
  3. Повторное использование: Interactor и Presenter не зависят от UIKit
  4. Читаемость: каждый компонент имеет одну четкую ответственность
  5. Безопасность типов: компилятор проверяет соответствие структур данных между компонентами

Clean Swift обеспечивает детерминированную, предсказуемую передачу данных через формальные контракты, что особенно важно в больших проектах с множеством разработчиков и сложной бизнес-логикой.

Как происходит передача данных между модулями в Clean Swift? | PrepBro