MVC (Model-View-Controller) — un pattern arhitectural care împarte aplicația în trei componente: Model răspunde de date și logica de business, View — de interfața utilizatorului, Controller — de procesarea intrărilor și coordonarea Model și View. În iOS, MVC se implementează prin UIViewController, în Android — prin Activity și Fragment. MVC rămâne pattern-ul de bază pe care sunt construite MVVM, MVP și Clean Architecture. Mai multe — pe MVC in Cocoa Core.
Principalele
MVC (Model-View-Controller) — un pattern arhitectural propus de Trygve Reenskaug în 1979 pentru limbajul Smalltalk-80. Pattern-ul împarte aplicația în trei straturi: Model conține datele și logica de business, View răspunde de afișare, Controller procesează intrarea utilizatorului și actualizează Model și View. Separarea responsabilităților permite modificarea fiecărui strat independent — de exemplu, înlocuirea View de la UIKit la SwiftUI fără a schimba logica de business în Model.
Interacțiunea componentelor în MVC urmează un ciclu: utilizatorul interacționează cu View → Controller primește evenimentul → Controller actualizează Model → Model notifică Controller despre modificări → Controller actualizează View. În implementarea clasică, Model folosește pattern-ul Observer: la modificarea datelor, Model trimite notificări, Controller se abonează și actualizează View. În implementarea Apple, Key-Value Observing (KVO) sau NotificationCenter îndeplinesc acest rol.
| Componentă | Responsabilitate | Exemplu în iOS | Exemplu în Android |
|---|---|---|---|
| Model | Date, logică de business, rețea | Struct User, CoreData | Data class, Repository |
| View | Afișare UI | Storyboard, XIB, UIView | Layout XML, Jetpack Compose |
| Controller | Procesare intrare, coordonare | UIViewController | Activity, Fragment |
MVC în dezvoltarea modernă de mobile este folosit mai rar decât acum 10 ani, dar rămâne obligatoriu de înțeles. Apple recomandă MVC pentru ecrane simple în aplicații UIKit. Google nu recomandă MVC pur pentru Android — documentația oficială sugerează MVVM cu Jetpack. Totuși, cunoașterea MVC este necesară pentru lucrul cu proiecte legacy și pentru înțelegerea evoluției pattern-urilor arhitecturale.
Apple MVC — o implementare personalizată a pattern-ului încorporată în UIKit. UIViewController îndeplinește rolul de Controller: gestionează ciclul de viață al ecranului (viewDidLoad, viewWillAppear, viewDidDisappear), procesează atingerile și acțiunile utilizatorului, actualizează View prin IBOutlets. View este creat în Interface Builder (storyboard sau XIB) sau programatic. Model — orice obiecte de date: servicii de rețea, stive CoreData, structuri Swift.
final class UserViewController: UIViewController {
// View (prin outlet storyboard)
@IBOutlet private var nameLabel: UILabel!
@IBOutlet private var emailLabel: UILabel!
// Model
private let userService = UserService()
override func viewDidLoad() {
super.viewDidLoad()
loadUser()
}
private func loadUser() {
userService.fetchUser { [weak self] user in
// Controller actualizează View
self?.nameLabel.text = user.name
self?.emailLabel.text = user.email
}
}
}
Problema Apple MVC — View și Controller sunt strâns legate. UIViewController gestionează simultan și View, și logica. Storyboard stochează View în XML, dar controlerul are referințe directe la elementele UI prin IBOutlets. Aceasta încalcă principiul responsabilității unice: controlerul răspunde de ciclul de viață, delegăți, datasource, target-action și animații. Ca rezultat, un ecran standard al unei aplicații iOS conține 200–500 de linii în controler.
Ciclul de viață ViewController — Apple oferă 6 metode ale ciclului de viață: loadView (crearea manuală a View), viewDidLoad (după încărcarea View în memorie), viewWillAppear (înainte de apariția pe ecran), viewDidAppear (după animație), viewWillDisappear (înainte de a părăsi ecranul), viewDidDisappear (după părăsire). Fiecare metodă — un loc pentru plasarea logicii în MVC. Utilizarea acestor metode pentru logica de business accelerează creșterea controlerului.
Android MVC — Activity și Fragment îndeplinesc rolul de Controller, fișierele layout XML — View, orice clasă POJO cu date — Model. Activity gestionează ciclul de viață al ecranului: onCreate, onStart, onResume, onPause, onStop, onDestroy. Fragment — sub-ecran în interiorul Activity cu propriul ciclu de viață. View (XML) este separat de Controller și se încarcă prin setContentView sau LayoutInflater. Model — repositorii, baze de date, apeluri de rețea.
class UserActivity : AppCompatActivity() {
// View prin layout XML
private lateinit var binding: ActivityUserBinding
// Model
private val userRepository = UserRepository()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityUserBinding.inflate(layoutInflater)
setContentView(binding.root)
loadUser()
}
private fun loadUser() {
userRepository.getUser { user ->
runOnUiThread {
binding.nameText.text = user.name
binding.emailText.text = user.email
}
}
}
}
Android ViewBinding și DataBinding — instrumente moderne care reduc cuplarea Controller și View. ViewBinding generează o clasă cu referințe directe la View din XML, eliminând findViewById. DataBinding adaugă posibilitatea de a lega datele cu UI în marcajul XML prin @{user.name}. DataBinding este un pas către MVVM, deoarece permite transmiterea datelor din Model în View fără cod în Activity. Google recomandă DataBinding pentru toate proiectele noi.
Ciclul de viață Android este mai complex decât iOS: Activity poate fi distrusă și recreată la rotirea ecranului, lipsa de memorie sau schimbarea configurației. În MVC pur, controlerul (Activity) conține logică care se pierde la distrugere. Aceasta necesită salvarea stării prin onSaveInstanceState sau ViewModel din Jetpack, ceea ce depășește cadrul MVC-ului pur și apropie arhitectura de MVVM.
Massive View Controller — termenul care descrie principala problemă a MVC în dezvoltarea de mobile. Controlerul în iOS și Android își asumă prea multe responsabilități: procesarea intrărilor, validarea datelor, interacțiunea cu rețeaua, navigarea, stocarea în cache, animațiile, gestionarea ciclului de viață. Ca rezultat, controlerul crește la 500–2000 de linii de cod, devenind dificil de citit, testat și întreținut.
Cauzele Massive View Controller — arhitectura UIKit și Android Framework stimulează plasarea logicii în controler. Apelurile de rețea, procesarea JSON, navigarea — toate acestea se scriu natural în Activity sau UIViewController, deoarece au acces la ciclul de viață și UI. Dezvoltatorul trebuie să scoată conștient logica în clase separate (Service, Manager, Interactor), ceea ce necesită disciplină și înțelegerea principiilor arhitecturale.
| Problemă MVC | Descriere | Soluție |
|---|---|---|
| Cuplare puternică | Controller cunoaște View și Model | MVVM — ViewModel nu cunoaște View |
| Dificultate testare | Controller depinde de UIKit/Android | Externalizarea logicii în servicii |
| Ciclu de viață | Starea se pierde la rotire | ViewModel din Jetpack/SwiftUI |
| Lipsă navigare | Controller gestionează tranzițiile | Pattern Coordinator, Router |
Testarea MVC — Model se testează izolat cu teste unitare. Testarea Controller este dificilă din cauza dependenței de UIKit/UIFoundation. XCTest nu permite crearea UIViewController fără fereastră de vizualizare. Pentru Android, ActivityTestRule și Robolectric rezolvă parțial problema, dar testele sunt lente. View de obicei nu se testează cu teste unitare — pentru UI se folosesc teste de captură ecran și teste UI (XCUITest, Espresso).
Când MVC este justificat — ecrane simple cu unul-două elemente (ecran de autentificare, profil, setări). Prototipuri și MVP pentru verificarea ipotezelor — MVC se scrie mai rapid fără straturi suplimentare. Proiecte cu bază de cod mică până la 10–15 ecrane. În proiecte complexe, MVC duce la acumularea de datorie tehnică și necesită refactorizare la fiecare 6–12 luni.
MVC vs MVVM — diferența principală: în MVVM controlerul este înlocuit cu ViewModel, care nu are referință la View. Datele sunt transmise prin Observable (SwiftUI), LiveData/StateFlow (Android) sau Combine/RxSwift. ViewModel se testează cu teste unitare fără dependențe UI. Apple recomandă MVVM cu SwiftUI din 2019, Google — MVVM cu LiveData/Flow ca arhitectură oficială Android. MVVM necesită mai mult cod pentru legare, dar îmbunătățește semnificativ testabilitatea.
MVC vs MVP — în MVP (Model-View-Presenter) Presenter este un strat testabil care primește View printr-o interfață. Spre deosebire de MVC, unde Controller gestionează direct View prin UIKit, Presenter nu depinde de framework — lucrează prin abstracția ViewInterface. MVP a fost popular în dezvoltarea Android până la apariția Jetpack și este folosit în proiecte vechi. Presenter trăiește mai mult decât Activity și păstrează starea la rotirea ecranului.
MVC vs Clean Architecture — Clean Architecture adaugă straturi Use Cases (Interactors), Entities, Gateways și Repository. MVC rămâne în stratul Presentation, dar logica de business este mutată în stratul Domain cu Use Cases. Clean Architecture rezolvă problema Massive View Controller radical — Controller conține doar apeluri Use Cases și actualizarea View. Dezavantajul este creșterea semnificativă a numărului de clase și fișiere, ceea ce este justificat pentru proiecte cu 50+ ecrane.
// MVC în iOS: Controller conține totul
class OrderViewController: UIViewController {
func placeOrder() {
// Validare + rețea + actualizare UI
guard Validation.isValid(total) else { return }
NetworkService.shared.submit(order) { [weak self] result in
self?.handleResult(result)
}
}
}
// MVVM: logica în ViewModel
class OrderViewModel: ObservableObject {
@Published var state: OrderState = .idle
func placeOrder() { /* logică de afaceri */ }
}
Alegerea arhitecturii depinde de mărimea echipei, proiect și testabilitatea necesară. Pentru o echipă de 1–2 dezvoltatori și un proiect de până la 20 de ecrane, este potrivit MVVM. Pentru o echipă mare de la 5 dezvoltatori și un proiect de la 50 de ecrane — Clean Architecture cu structură modulară. MVC rămâne relevant pentru înțelegerea evoluției arhitecturilor, pentru suportul proiectelor legacy și pentru ecrane simple în UIKit fără logică de business complexă.
Întrebări frecvente
Principala problemă este Massive View Controller. În iOS, controlerul UIViewController răspunde de tot: procesarea intrărilor, actualizarea View, lucrul cu rețeaua, navigarea și ciclul de viață. În Android, Activity/Fragment îndeplinește funcții similare. Ca rezultat, controlerul crește la mii de linii de cod, devine dificil de testat și întreținut, încălcând principiul responsabilității unice.
În MVC, controlerul actualizează direct View și procesează intrarea utilizatorului. În MVVM, rolul controlerului este îndeplinit de ViewModel, care nu are referință la View — datele sunt transmise prin mecanisme de legare. MVVM se testează mai bine, deoarece ViewModel nu depinde de UIKit sau Android Framework. Apple recomandă MVVM cu SwiftUI, Google — MVVM cu Jetpack Compose.
Da, MVC rămâne un pattern funcțional pentru ecrane simple și prototipuri. Apple recomandă MVC pentru aplicații UIKit cu ecrane simple. Pentru proiecte complexe cu multe ecrane, cereri de rețea și stocare în cache, este mai bine să alegeți MVVM, VIPER sau Clean Architecture. Dezvoltatorilor începători li se recomandă să stăpânească MVC înainte de a studia pattern-uri mai complexe.
Model se testează izolat — sunt obiecte obișnuite de date și logică de business. Controller este dificil de testat din cauza dependenței de UIKit sau Android Framework. Se recomandă mutarea logicii de business din controler în servicii sau interactori separați, care se testează cu teste unitare. View de obicei nu se testează cu teste unitare — pentru el se folosesc teste UI și teste de captură ecran.
Pe iOS — MVVM cu SwiftUI și Combine, standardul Apple din 2019. Pe Android — MVVM cu LiveData sau StateFlow, recomandat oficial de Google. Pentru proiecte mari cu echipe de la 5 dezvoltatori — Clean Architecture cu VIPER pe iOS sau Clean Architecture pe Android cu împărțire pe module după funcționalități. Pentru proiecte legacy cu MVC — refactorizare treptată cu mutarea logicii în servicii separate.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și