Що таке MVC в iOS-розробці та чим відрізняється від MVP і MVVM?

30
8 хв.

Архітектурний патерн визначає, як організований код застосунку: хто відповідає за дані, хто – за відображення, хто – за логіку. Вибір патерну впливає на тестованість, швидкість розробки і те, наскільки легко підтримувати проєкт через рік. Патерни проєктування MVC, MVP і MVVM – три найпоширеніших підходи в iOS, і у кожного є своя сфера застосування.

Що таке патерн MVC і навіщо він потрібен?

MVC патерн (Model-View-Controller) – це архітектурний шаблон, який ділить застосунок на три компоненти з чіткими зонами відповідальності. Згідно з офіційною документацією Apple, MVC є базовим патерном Cocoa і рекомендований як відправна точка для будь-якого iOS-застосунку.

Model – зберігає дані та бізнес-логіку. Не знає нічого про View і Controller. Приклад: структура User, клас UserService, робота з CoreData або мережею.

View – відповідає за відображення. UILabel, UIButton, UITableView. Не містить логіки – лише рендеринг даних, які їй передали.

Controller – медіатор між Model і View. Отримує дані з Model, форматує їх і передає у View. Обробляє дії користувача та ініціює зміни в Model.

MVC простими словами: Controller – це менеджер. View – вітрина магазину. Model – склад. Покупець (користувач) бачить лише вітрину, менеджер вирішує, що на ній показати і як обробити замовлення.

Як влаштований MVC в iOS: Model, View, Controller

MVC iOS – це не зовсім класичний Gang of Four MVC. Apple модифікувала патерн для UIKit: у класичній версії View і Model можуть спілкуватися безпосередньо, в Apple MVC – ні. View взаємодіє лише з Controller через target-action і delegation, Controller звертається до Model і оновлює View.

Практично це означає: UIViewController в iOS завжди є Controller. Він володіє View (через IBOutlet або programmatic layout) і реагує на події View (через IBAction або делегування). Саме тому на UIViewController лягає величезне навантаження.

Приклад типової зв'язки в UIKit:


// Модель
struct Article { let title: String; let body: String }
 
// View – UITableViewCell (налаштовується ззовні)
// Controller
class ArticleListVC: UIViewController, UITableViewDataSource {
	var articles: [Article] = []
	func viewDidLoad() {
    	super.viewDidLoad()
    	loadArticles()  // звернення до Model
	}
	func tableView(_ tv: UITableView, cellForRowAt ip: IndexPath) -> UITableViewCell {
    	let cell = tv.dequeueReusableCell(withIdentifier: "Cell", for: ip)
    	cell.textLabel?.text = articles[ip.row].title  // оновлення View
    	return cell
	}
}

Вибір технологічного стеку для iOS – окрема тема: Swift vs Objective-C, UIKit vs SwiftUI, нативна розробка vs кросплатформа. Огляд підходів – у матеріалі «Оптимальні технології та мови для розробки застосунків на iOS».

Чому MVC призводить до Massive ViewController?

Проблема Massive View Controller – прямий наслідок Apple MVC. Оскільки Controller – єдиний медіатор між View і Model, до нього поступово потрапляє все: мережеві запити, форматування даних, навігаційна логіка, обробка помилок, аналітика. За спостереженнями команди Netguru, UIViewController у реальних MVC-проєктах нерідко виростає до 1 000-2 000 рядків коду.

Типовий вміст «роздутого» ViewController у MVC-проєкті: завантаження даних із мережі (виклик API, парсинг відповіді), форматування дат, рядків, валют для відображення, обробка станів (loading / success / error), навігація між екранами, аналітика та логування подій, керування UITableView або UICollectionView через delegate і dataSource.

Головний наслідок – низька тестованість. Юніт-тест для Controller майже неможливий без запуску UIKit: не можна перевірити бізнес-логіку в ізоляції, якщо вона перемішана з кодом оновлення UI.

MVC vs MVP: у чому різниця?

MVC vs MVP – це передусім різниця в тому, хто знає про UIKit. У MVC Controller безпосередньо працює з UIView, UIButton, UILabel. У MVP вводиться Presenter – об'єкт, який містить всю логіку екрана, але нічого не знає про UIKit. View (UIViewController) реалізує протокол і просто виконує команди Presenter.

Приклад: у MVC метод loginTapped() у ViewController сам валідує поля, викликає API та оновлює UI. У MVP – ViewController викликає presenter.loginTapped(email:, password:), а Presenter виконує логіку і викликає view.showError() або view.navigateToHome() через протокол.


// MVP: протокол View
protocol LoginView: AnyObject {
	func showError(_ message: String)
	func navigateToHome()
}
 
// Presenter – не імпортує UIKit
class LoginPresenter {
	weak var view: LoginView?
	func loginTapped(email: String, password: String) {
    	guard !email.isEmpty else { view?.showError("Email порожній"); return }
    	// логіка автентифікації
    	view?.navigateToHome()
	}
}

Ключовий виграш MVP: Presenter тестується як звичайний Swift-клас без емулятора. Достатньо передати мок-об'єкт View через протокол і викликати метод – вся поведінка перевіряється в unit-тесті.

У чому відмінність MVC від MVVM?

Різниця MVC і MVVM – у механізмі зв'язку між View і даними. У MVC Controller вручну оновлює View: отримав дані → написав label.text = value. У MVVM ViewModel публікує дані через Combine (або RxSwift), а View підписується на зміни та оновлюється автоматично без явних викликів з боку ViewModel.

Приклад біндингу через Combine у MVVM:


class ArticleViewModel: ObservableObject {
	@Published var title: String = ""
	private var article: Article
	init(article: Article) {
    	self.article = article
    	self.title = article.title
	}
}
 
// View (ViewController)
viewModel.$title
	.receive(on: RunLoop.main)
	.assign(to: \.text, on: titleLabel)
	.store(in: &cancellables)

MVC vs MVVM: ViewController у MVVM стає «тонким» – він лише підписується на публікації ViewModel і передає дії користувача. ViewModel не знає про існування View, що робить її повністю тестованою. Окрема перевага: MVVM нативно сумісний із SwiftUI через @ObservedObject і @StateObject.

Коли використовувати MVC, а коли переходити на MVP або MVVM?

Порівняльна таблиця: MVC vs MVP vs MVVM
КритерійMVCMVPMVVM
Складність входу🟢 Низька🟡 Середня🔴 Вище середнього
Тестованість🔴 Низька🟢 Висока🟢 Висока
Обсяг коду🟢 Мінімальний🟡 Середній🟡 Середній
Масштаб проєкту🟢 Малий / Прототип🟡 Середній🟢 Середній / Великий
Популярність в iOS (UIKit)🟢 Дуже висока🟡 Середня🟢 Висока
Сумісність із SwiftUI🟡 Обмежена🟡 Обмежена🟢 Нативна

Коли обирати кожен патерн:

MVC – прототип, MVP продукту, невеликий застосунок з 3-5 екранами, команда початківців або жорсткі дедлайни. MVC iOS – єдиний патерн, для якого Apple надає готові шаблони в Xcode.

MVP – UIKit-проєкт середнього розміру, де важлива тестованість бізнес-логіки, але команда не хоче вивчати реактивне програмування. Добре працює, якщо екранів 10–30 і у кожного екрана своя чітка логіка.

MVVM – активне використання Combine або SwiftUI, складні екрани з кількома джерелами даних, проєкт із розвиненою культурою unit-тестування. Різниця між MVC MVP MVVM стає принциповою, коли застосунок переходить межу в 50+ екранів і кілька команд розробників.

При виборі патерну враховуйте й інші чинники: досвід команди, наявність CI/CD, вимоги до тестованості. Якщо ви плануєте iOS-застосунок з нуля – розробка мобільних застосунків для iOS з досвідченою командою дозволяє обрати архітектуру під конкретні завдання проєкту.

Висновок

MVC – це не «поганий» патерн, це патерн із конкретною сферою застосування. Для швидкого прототипу або невеликого застосунку він залишається оптимальним вибором. Проблеми починаються, коли MVC застосовують до великого проєкту без усвідомлення обмежень – тоді Controller неминуче роздувається. MVP вирішує проблему тестованості без зміни технологічного стеку. MVVM дає максимальну гнучкість при роботі з реактивними фреймворками і SwiftUI. MVC – це базовий патерн iOS-екосистеми, і розуміння різниці між усіма трьома підходами – частина базової грамотності iOS-розробника.

Готовий застосунок зрештою проходить публікацію в App Store – покроковий процес описаний у матеріалі «Як опублікувати застосунок в App Store». Якщо ви шукаєте команду для розробки мобільного застосунку під ключ, архітектурний вибір – одне з перших питань, яке варто обговорити на старті.

Часті запитання
Залежить від масштабу та стеку. Якщо проєкт невеликий і використовується UIKit – MVC дасть швидкість старту. Якщо проєкт на SwiftUI або планується активне використання Combine – MVVM нативніший і дозволить уникнути Massive ViewController з першого екрана. Різниця між MVC і MVVM стає відчутною при масштабуванні: те, що зручно для 5 екранів, створює проблеми при 50.
Так, і це поширена практика. Нові екрани пишуться на MVVM, старі залишаються на MVC за відсутності ресурсів на рефакторинг. Важливо домовитися про межі: який патерн використовується за замовчуванням, і не змішувати логіку різних патернів в одному модулі. Хаотичне змішування гірше за будь-який послідовно застосований патерн.

Офіційний старт – документація Apple щодо MVC у Cocoa. Для розуміння різниці між патернами в UIKit-контексті – стаття Bohdan Orlov «iOS Architecture Patterns» на Medium. Огляд інструментів для розробки iOS і Android-застосунків – у матеріалі «Топ-10 програм для створення застосунків».

18 вересня 2026
5 / 5 (1 голос)