В каких случаях выбирают архитектурный паттерн MVP для iOS?

Ответ

Model-View-Presenter (MVP) — хороший выбор, когда нужна лучшая тестируемость и разделение ответственности по сравнению с MVC, но без сложности MVVM.

Ключевые сценарии использования:

  1. Проекты средней сложности – где бизнес-логика становится объемной, но реактивное программирование не требуется.
  2. Акцент на модульное тестированиеPresenter содержит логику и не зависит от UIKit, что делает его легким для тестирования.
  3. Четкое разделение слоев – View отвечает только за отображение, Presenter — за логику представления и обработку действий пользователя.
  4. Постепенная миграция с MVC – MVP логически следует за MVC, что упрощает рефакторинг.

Пример реализации на Swift:

// View Protocol
protocol LoginViewProtocol: AnyObject {
    func showLoading(_ isLoading: Bool)
    func showError(message: String)
    func navigateToHome()
}

// Presenter
class LoginPresenter {
    weak var view: LoginViewProtocol?
    private let authService: AuthServiceProtocol

    init(authService: AuthServiceProtocol) {
        self.authService = authService
    }

    func loginButtonTapped(email: String, password: String) {
        view?.showLoading(true)
        authService.login(email: email, password: password) { [weak self] result in
            self?.view?.showLoading(false)
            switch result {
            case .success:
                self?.view?.navigateToHome()
            case .failure(let error):
                self?.view?.showError(message: error.localizedDescription)
            }
        }
    }
}

Недостаток: Необходимость ручного обновления View и потенциальное увеличение количества протоколов.

Ответ 18+ 🔞

Слушай, а вот этот ваш MVP — он, блядь, как золотая середина, если надоел этот бардак в MVC, но влезать в реактивщину MVVM ещё страшновато. Ну, знаешь, когда уже хочется порядок, но чтобы мозги не вытекали.

Где его, сука, пристраивать?

  1. Проекты, где уже не игрушки, но ещё не адский enterprise — логика начинает пухнуть, как на дрожжах, но связывать всё реактивными потоками — это овердохуища работы. MVP тут в самый раз.
  2. Когда начальство орет «Надо тесты, блядь!» — а вся логика у тебя в ViewController приклеена к UIKit. Вот тут Presenter — спасение. Он же нихуя не знает про вьюхи, его голым юнитом потестил и спокоен, как удав.
  3. Чтоб каждый сидел на своей жопе ровно — Вьюха только рисует и тыкает кнопками. Презентер — это такой умный посредник, который всё решает и отдаёт вьюхе готовенькое. Модель... Ну, модель как модель, с данными работает.
  4. Когда из говняного MVC надо вылезать потихоньку — MVP из той же оперы, только чище. Не надо всё ломать, можно по кусочкам перетаскивать логику в презентеры. Удобно, ёпта!

Смотри, как это выглядит в коде, на примере какой-нибудь авторизации:

// Протокол для Вьюхи. Чтоб не привязываться к конкретной UIViewController-ше.
protocol LoginViewProtocol: AnyObject {
    func showLoading(_ isLoading: Bool) // Включи/выключи крутилку, ебанашка
    func showError(message: String) // Покажи ошибку, если пользователь — криворукий
    func navigateToHome() // Если всё ок — проваливай на следующий экран
}

// Сам Презентер, мозг операции.
class LoginPresenter {
    weak var view: LoginViewProtocol? // Ссылка на вьюху, но через протокол, чтоб не привязаться намертво
    private let authService: AuthServiceProtocol // Сервис для логина, инжектится, красота!

    init(authService: AuthServiceProtocol) {
        self.authService = authService
    }

    // Юзер тыкнул в кнопку "Войти". Вся логика здесь!
    func loginButtonTapped(email: String, password: String) {
        view?.showLoading(true) // Говорим вьюхе: "Хватит тыкать, жди!"
        authService.login(email: email, password: password) { [weak self] result in
            self?.view?.showLoading(false) // Говорим вьюхе: "Всё, можно снова тыкать"
            switch result {
            case .success:
                self?.view?.navigateToHome() // Ура, пускаем дальше!
            case .failure(let error):
                self?.view?.showError(message: error.localizedDescription) // Объясняем юзеру, что он опять облажался
            }
        }
    }
}

А минусы-то где? Да вот же они, хитрая жопа! Надо будет вручную обновлять вьюху после каждого чиха. И этих протоколов для вьюх может развестись, как тараканов, если проект большой. Но за тестируемость и порядок иногда стоит и потерпеть, блядь.