Налаштування архітектури MVP для iOS: шаблон і практика

Налаштування архітектури MVP для iOS-додатку Уявіть: кодова база UIKit-додатку розрослася до 20+ екранів, кожен ViewController тягне 500+ рядків, а тести відсутні або вимагають запуску симулятора. Ви пробували MVVM, але зв'язка Combine з `@Published` не вписалася — проєкт занадто старий, або кома

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Налаштування архітектури MVP для iOS: шаблон і практика
Середній
~2-3 дні

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Налаштування архітектури MVP для iOS-додатку

Уявіть: кодова база UIKit-додатку розрослася до 20+ екранів, кожен ViewController тягне 500+ рядків, а тести відсутні або вимагають запуску симулятора. Ви пробували MVVM, але зв'язка Combine з @Published не вписалася — проєкт занадто старий, або команда прийшла з Android з її MVP-культурою. Наша команда має досвід налаштування MVP на 15+ проєктах і гарантує працездатність шаблону з першого коміту. У цій статті розберемо ключові протоколи, ізоляцію UIKit і тестування без симулятора.

Wikipedia: Model-View-Presenter — це архітектурний патерн, в якому Presenter виступає посередником між View та Model. На iOS це особливо корисно для великих проєктів, де MVVM з Combine вимагає переписування коду під реактивний стек.

Чому MVP підходить для UIKit-проєктів?

Якщо ваш проєкт — не простий список з деталями, а складний багатоекранний UIKit, MVP дає чітке розділення: Presenter не бачить UIKit, ViewController тонший, тести пишуться без симулятора. На відміну від MVVM, де ViewModel підписується на Combine, MVP використовує прості протоколи та слабкі посилання. Це знижує поріг входу і не вимагає переписування коду під реактивний стек. Такий підхід є елементом чистої архітектури iOS, оскільки залежності направлені від зовнішніх шарів до ядра.

Що таке MVP на iOS і в чому відмінність від MVVM?

За визначенням Model-View-Presenter — це архітектурний патерн, в якому Presenter виступає посередником між View та Model. У MVVM ViewController підписується на @Published-властивості ViewModel через Combine. У MVP Presenter не знає про UIKit: він спілкується з протоколом View, який реалізує ViewController. Немає біндінгів, немає реактивності — повна контрольованість потоку даних.

// View protocol — інтерфейс для Presenter protocol ProfileView: AnyObject { func showUser(_ user: User) func showLoading(_ isLoading: Bool) func showError(_ message: String) } // Presenter — чистий Swift, нічого UIKit final class ProfilePresenter { weak var view: ProfileView? private let userRepository: UserRepository init(userRepository: UserRepository) { self.userRepository = userRepository } func viewDidLoad() { view?.showLoading(true) Task { do { let user = try await userRepository.fetchCurrentUser() await MainActor.run { view?.showLoading(false) view?.showUser(user) } } catch { await MainActor.run { view?.showLoading(false) view?.showError(error.localizedDescription) } } } } } // ViewController — тонкий, тільки UI final class ProfileViewController: UIViewController, ProfileView { private var presenter: ProfilePresenter! override func viewDidLoad() { super.viewDidLoad() presenter.viewDidLoad() } func showUser(_ user: User) { nameLabel.text = user.name avatarImageView.load(url: user.avatarURL) } func showLoading(_ isLoading: Bool) { isLoading ? activityIndicator.startAnimating() : activityIndicator.stopAnimating() } func showError(_ message: String) { // Toast або Alert } } 

Ключовий момент: weak var view: ProfileView? — слабке посилання обов'язкове, інакше retain cycle. Presenter тримає View, View тримає Presenter — один з них має бути weak.

Як тестувати Presenter без симулятора?

Головна перевага MVP — Presenter тестується без симулятора. Ось приклад з моком:

final class MockProfileView: ProfileView { var didShowUser = false var isLoading = false func showUser(_ user: User) { didShowUser = true } func showLoading(_ isOn: Bool) { isLoading = isOn } func showError(_ message: String) { /* ignore */ } } func testViewDidLoad_success() async { let mockView = MockProfileView() let mockRepository = MockUserRepository(result: .success(User.fixture)) let sut = ProfilePresenter(userRepository: mockRepository) sut.view = mockView sut.viewDidLoad() // Невелика пауза для async Task try await Task.sleep(nanoseconds: 100_000_000) XCTAssertTrue(mockView.didShowUser) XCTAssertFalse(mockView.isLoading) } 

Тест займає мілісекунди, не вимагає XCUITest. Покриття коду такими тестами досягає 80%, а економія коштів на регресі — до 40% бюджету. Порівняйте: типова MVVM-ViewModel з Combine вимагає налаштування XCTestExpectation або Sink — MVP тут значно простіший і швидший.

Що входить у налаштування MVP?

При замовленні налаштування MVP ви отримуєте:

  • Повні Swift-файли модуля: Presenter, ViewController, Router.
  • Unit-тести Presenter (5–10 кейсів на модуль, покриття 80%).
  • Інтеграційні інструкції для додавання нових екранів.
  • Навчання команди (1–2 дзвінки з демонстрацією).

Робота займає 2–3 дні для нового проєкту. Зв'яжіться з нами для оцінки обсягу міграції існуючих екранів. Отримайте консультацію щодо впровадження MVP у ваш проєкт.

Навігація в MVP: що таке Router / Wireframe?

Presenter не повинен керувати навігацією безпосередньо — це порушує Single Responsibility. Класичне рішення: Router (або Wireframe в оригінальних термінах MVP):

protocol ProfileRouter: AnyObject { func navigateToEditProfile(user: User) func navigateToSettings() } 

Конкретний ProfileRouterImpl працює з UINavigationController — UIKit-залежність ізольована. Presenter отримує Router через DI і викликає router.navigateToEditProfile(user:) — без знання того, що відбувається під капотом.

Як мігрувати MVC на MVP?

Міграція існуючого MVC-екрану на MVP — задача на 4–8 годин на екран. Створіть протокол View, виділіть логіку в Presenter, додайте Router. Перенесіть залежність від Model в Presenter. Реалізуйте View у ViewController. Тестуйте Presenter. Такий покроковий план застосовний для будь-якого екрану, а підсумкова архітектура стає модульною і тестованою.

Покрокове налаштування MVP для нового проєкту

  1. Визначте модулі. Кожен екран — окремий модуль з протоколами View, Presenter, Router.
  2. Напишіть протоколи. View — тільки методи відображення; Presenter — методи життєвого циклу та обробки подій; Router — навігаційні методи.
  3. Реалізуйте Presenter. Вся логіка, робота з сервером/БД. Жодного UIKit.
  4. Реалізуйте View (ViewController). Прокидайте виклики до Presenter.
  5. Реалізуйте Router. Створіть клас, який використовує UINavigationController для переходів.
  6. Налаштуйте DI. Використовуйте фабрику модулів або Swinject для компонування залежностей.
  7. Напишіть тести. Покрийте кожен метод Presenter (5–10 кейсів на модуль).
Крок Тривалість
Визначення модулів 1–2 год
Протоколи та Presenter 3–4 год
View та Router 2–3 год
DI та фабрика 1–2 год
Тести (10 кейсів) 2–3 год
Інтеграція 1 год

Порівняння MVP і MVVM

Характеристика MVP MVVM
Залежність від UIKit Ні (Presenter) Ні (ViewModel)
Біндінг Відсутній Combine (або Rx)
Тестування без симулятора Так Так (із застереженнями)
Складність на SwiftUI Не застосовний Природний
Стек у проєкті UIKit UIKit / SwiftUI

Які типові помилки допускають при впровадженні MVP?

  • Забути weak на view — retain cycle, витік пам'яті. Завжди використовуйте weak var view: ViewProtocol?.
  • Змішувати логіку навігації в Presenter — виділіть Router.
  • Не тестувати Presenter — втрачаєте головну перевагу MVP. Покривайте моками.
  • Переускладнювати протоколи — один метод на екран замість дроблення. Тримайте кількість методів View у розумних межах (5–7).

Замовте налаштування MVP для вашого проєкту — отримайте готовий шаблон за 2–3 дні. Ми гарантуємо, що ваш проєкт отримає структуру, зручну для тестування, а команда — робочий процес без зайвого оверхеду. Зв'яжіться з нами для консультації.