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

В каком виде презентер получает данные?

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

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

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

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

Как презентер получает данные в архитектуре VIPER?

В архитектуре VIPER презентер выступает центральным координатором между модулями, отвечающим за бизнес-логику и подготовку данных для отображения в View. Он получает данные через четко определенные механизмы взаимодействия с другими компонентами, преимущественно через Interactor и Entity, но также может получать данные напрямую от View или через Router в определенных сценариях.

Основные источники данных для презентера:

1. От Interactor через протоколы (контракты)

Это основной и наиболее чистый способ. Презентер декларирует свои потребности через Input Protocol, а Interactor реализует Output Protocol, по которому передает результаты.

// Протокол для Interactor -> Presenter
protocol ListInteractorOutputProtocol: AnyObject {
    func didFetchUsers(_ users: [UserEntity])
    func didFailToFetchUsers(with error: Error)
}

// Протокол для Presenter -> Interactor
protocol ListInteractorInputProtocol {
    func fetchUsers()
}

// Presenter реализует выходный протокол Interactor
class ListPresenter: ListInteractorOutputProtocol {
    weak var view: ListViewInputProtocol?
    var interactor: ListInteractorInputProtocol?

    func fetchData() {
        interactor?.fetchUsers() // Запрос данных
    }

    // Получение данных от Interactor
    func didFetchUsers(_ users: [UserEntity]) {
        let viewModels = users.map { UserViewModel(from: $0) }
        view?.displayUsers(viewModels) // Передача подготовленных данных в View
    }

    func didFailToFetchUsers(with error: Error) {
        view?.displayError(message: error.localizedDescription)
    }
}

2. От View через события пользователя

Презентер получает данные в виде пользовательских событий или действий, которые View передает ему через свой Input Protocol. Это не "данные" в виде моделей, а триггеры для их получения.

// View сообщает Presenter о действии пользователя
protocol ListViewOutputProtocol {
    func viewDidLoad()
    func userDidSelectItem(at index: Int)
    func userDidSearch(with query: String)
}

class ListPresenter {
    func userDidSearch(with query: String) {
        // Presenter может либо передать query Interactor для фильтрации,
        interactor?.filterUsers(with: query)
        // либо выполнить простую логику самостоятельно.
    }
}

3. От Router при навигации

В некоторых случаях Router может передавать презентеру начальные параметры или конфигурацию при создании модуля.

class ListRouter {
    static func assembleModule(with initialData: SomeInitialConfig) -> UIViewController {
        let presenter = ListPresenter()
        presenter.initialConfiguration = initialData // Данные переданы напрямую
        // ... остальная сборка модуля
        return viewController
    }
}

4. Прямая обработка и трансформация Entity

После получения "сырых" Entity от Interactor, презентер выполняет их трансформацию в ViewModels (или другие структуры), удобные для View. Это его ключевая ответственность.

struct UserEntity {
    let id: Int
    let firstName: String
    let lastName: String
    let registrationDate: Date
}

struct UserViewModel {
    let fullName: String
    let registrationYear: String

    init(from entity: UserEntity) {
        self.fullName = "\(entity.firstName) \(entity.lastName)"
        let year = Calendar.current.component(.year, from: entity.registrationDate)
        self.registrationYear = "Registered in \(year)"
    }
}

Ключевые принципы получения данных:

  • Через протоколы: Все взаимодействие строго типизировано и инкапсулировано.
  • Декомпозиция ответственности: Interactor получает "сырые" данные из сети/базы, Presenter их готовит для отображения.
  • Реактивная или блочная модель: Передача может быть реализована как через callback-блоки (как в примерах выше), так и через RxSwift или Combine для реактивных потоков.
  • Presenter никогда не знает о конкретных классах: Он работает только с абстракциями (протоколами), что обеспечивает тестируемость и гибкость.

Таким образом, презентер в VIPER получает данные преимущественно от Interactor в ответ на свои запросы или события от View, затем трансформирует их согласно бизнес-логике и передает в View для окончательного отображения. Этот четкий поток данных предотвращает смешение ответственности и делает код каждого компонента модульным и легко тестируемым.

В каком виде презентер получает данные? | PrepBro