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

Как данные из интерактора поступают в презентер?

2.0 Middle🔥 162 комментариев
#Архитектура и паттерны

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

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

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

Взаимодействие между Interactor и Presenter в архитектуре VIPER/Clean Swift

В архитектурах VIPER и Clean Swift (также известной как VIP), где применяется паттерн Interactor, передача данных от интерактора к презентеру происходит через четко определенные контракты (protocols) и модели данных. Этот механизм обеспечивает разделение ответственности, тестируемость и соблюдение принципа Single Responsibility.

Основной механизм передачи данных

Interactor отвечает за бизнес-логику: получение данных из сети, базы данных, или их обработку. После завершения своей работы он передает результат Presenter'у, который форматирует эти данные для отображения на View.

1. Определение контрактов (протоколов)

Каждый модуль (Interactor, Presenter, View) объявляет протокол для своего "выхода" (output), через который он общается со следующим слоем.

// Протокол для выхода Interactor'а (то, что он может передать)
protocol MyInteractorOutput: AnyObject {
    func didFetchDataSuccess(_ response: MyModel.Response)
    func didFetchDataFailure(_ error: Error)
}

// Протокол для выхода Presenter'а (не относится к вопросу, но для контекста)
protocol MyPresenterOutput: AnyObject {
    func displayData(_ viewModel: MyModel.ViewModel)
    func displayError(_ message: String)
}

2. Структурирование данных через модели

Данные передаются в виде строго типизированных моделей (обычно вложенных структур), что исключает передачу "сырых" сущностей.

enum MyModel {
    // Запрос от View к Interactor (через Presenter)
    struct Request {
        let userId: String
    }
    
    // Ответ от Interactor к Presenter (содержит "сырые" бизнес-данные)
    struct Response {
        let user: UserEntity
        let timestamp: Date
    }
    
    // ViewModel от Presenter к View (отформатированные для UI данные)
    struct ViewModel {
        let userName: String
        let formattedDate: String
    }
}

3. Процесс передачи данных

  1. Interactor получает задачу (например, по запросу от Presenter).
  2. После выполнения бизнес-логики (загрузка, обработка) Interactor вызывает метод своего output (которым является Presenter).
  3. Presenter, реализующий MyInteractorOutput, принимает Response-модель, трансформирует ее в ViewModel и передает дальше во View.
// Пример в Interactor
class MyInteractor {
    weak var output: MyInteractorOutput? // Ссылка на Presenter
    let service: NetworkService
    
    func fetchData(for request: MyModel.Request) {
        service.loadUser(id: request.userId) { [weak self] result in
            switch result {
            case .success(let userEntity):
                let response = MyModel.Response(user: userEntity, timestamp: Date())
                self?.output?.didFetchDataSuccess(response) // Передача данных в Presenter
            case .failure(let error):
                self?.output?.didFetchDataFailure(error) // Передача ошибки
            }
        }
    }
}

// Пример в Presenter
class MyPresenter: MyInteractorOutput {
    weak var view: MyPresenterOutput? // Ссылка на View
    
    func didFetchDataSuccess(_ response: MyModel.Response) {
        // Форматирование данных для View
        let userName = response.user.name.capitalized
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .medium
        let formattedDate = dateFormatter.string(from: response.timestamp)
        
        let viewModel = MyModel.ViewModel(userName: userName, formattedDate: formattedDate)
        view?.displayData(viewModel) // Передача во View
    }
    
    func didFetchDataFailure(_ error: Error) {
        let message = "Ошибка: \(error.localizedDescription)"
        view?.displayError(message)
    }
}

Ключевые особенности и преимущества

  • Слабая связность: Interactor ничего не знает о Presenter, кроме его протокола. Это позволяет легко менять реализацию или мокать зависимости в тестах.
  • Односторонний поток данных: Данные движутся в одном направлении: View → Presenter → Interactor → Presenter → View. Это упрощает отслеживание изменений состояния.
  • Тестируемость: Interactor можно тестировать отдельно, подменяя output-заглушкой. Presenter тестируется с моковым Interactor.
  • Форматирование в Presenter: Interactor возвращает "чистые" бизнес-данные (например, Date), а Presenter отвечает за их преобразование в удобный для отображения формат (например, строку). Это соответствует принципу Clean Architecture, где Presenter — это слой Interface Adapters.

Вариации в других архитектурах

  • В MVP (Model-View-Presenter) аналогом Interactor часто выступает Model или Use Case, и Presenter напрямую вызывает его методы, получая данные через замыкания или делегаты.
  • В VIPER иногда используют Router для передачи данных между модулями, но внутри модуля взаимодействие остается таким же: Interactor → Presenter.

Таким образом, передача данных от Interactor к Presenter — это не просто вызов метода, а строго типизированное взаимодействие через протоколы, обеспечивающее чистоту архитектуры и поддерживаемость кода.