MVC (Model-View-Controller) — ett arkitekturmönster som delar upp applikationen i tre komponenter: Model ansvarar för data och affärslogik, View — för användargränssnittet, Controller — för bearbetning av indata och samordning av Model och View. I iOS implementeras MVC via UIViewController, i Android — via Activity och Fragment. MVC förblir grundmönstret som MVVM, MVP och Clean Architecture är byggda på. Mer — på MVC in Cocoa Core.
Huvudpunkter
MVC (Model-View-Controller) — ett arkitekturmönster som föreslogs av Trygve Reenskaug 1979 för språket Smalltalk-80. Mönstret delar upp applikationen i tre lager: Model innehåller data och affärslogik, View ansvarar för visning, Controller bearbetar användarindata och uppdaterar Model och View. Separation av ansvarsområden gör det möjligt att ändra varje lager oberoende — till exempel ersätta View från UIKit till SwiftUI utan att ändra affärslogiken i Model.
Interaktion av komponenter i MVC följer en cykel: användaren interagerar med View → Controller tar emot händelsen → Controller uppdaterar Model → Model meddelar Controller om ändringar → Controller uppdaterar View. I den klassiska implementeringen använder Model Observer-mönstret: när data ändras skickar Model meddelanden, Controller prenumererar och uppdaterar View. I Apples implementering utför Key-Value Observing (KVO) eller NotificationCenter denna roll.
| Komponent | Ansvarsområde | Exempel i iOS | Exempel i Android |
|---|---|---|---|
| Model | Data, affärslogik, nätverk | Struct User, CoreData | Data class, Repository |
| View | Visning av UI | Storyboard, XIB, UIView | XML-layout, Jetpack Compose |
| Controller | Bearbetning av indata, samordning | UIViewController | Activity, Fragment |
MVC i modern mobilutveckling används mer sällan än för 10 år sedan, men förblir obligatoriskt att förstå. Apple rekommenderar MVC för enkla skärmar i UIKit-applikationer. Google rekommenderar inte ren MVC för Android — officiell dokumentation föreslår MVVM med Jetpack. Kunskaper i MVC är dock nödvändiga för arbete med äldre projekt och för att förstå evolutionen av arkitekturmönster.
Apple MVC — en anpassad implementering av mönstret inbyggd i UIKit. UIViewController spelar rollen som Controller: hanterar skärmens livscykel (viewDidLoad, viewWillAppear, viewDidDisappear), bearbetar beröringar och användaråtgärder, uppdaterar View via IBOutlets. View skapas i Interface Builder (storyboard eller XIB) eller programmatiskt. Model — alla dataobjekt: nätverkstjänster, CoreData-stackar, Swift-strukturer.
final class UserViewController: UIViewController {
// View (via storyboard outlet)
@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 uppdaterar View
self?.nameLabel.text = user.name
self?.emailLabel.text = user.email
}
}
}
Problem med Apple MVC — View och Controller är tätt kopplade. UIViewController hanterar samtidigt både View och logik. Storyboard lagrar View i XML, men kontrollern har direkta referenser till UI-element via IBOutlets. Detta bryter mot principen om enskilt ansvar: kontrollern ansvarar för livscykel, delegater, datasource, target-action och animationer. Som ett resultat innehåller en standardskärm i en iOS-applikation 200–500 rader i kontrollern.
ViewController livscykel — Apple tillhandahåller 6 livscykelmetoder: loadView (manuell skapelse av View), viewDidLoad (efter att View har laddats i minnet), viewWillAppear (innan skärmen visas), viewDidAppear (efter animation), viewWillDisappear (innan skärmen lämnas), viewDidDisappear (efter att ha lämnat). Varje metod — en plats för att placera logik i MVC. Att använda dessa metoder för affärslogik påskyndar kontrollerns tillväxt.
Android MVC — Activity och Fragment spelar rollen som Controller, XML-layoutfiler — View, vilken POJO-klass som helst med data — Model. Activity hanterar skärmens livscykel: onCreate, onStart, onResume, onPause, onStop, onDestroy. Fragment — underskärm inuti Activity med egen livscykel. View (XML) är separerad från Controller och laddas via setContentView eller LayoutInflater. Model — databaser, databaser, nätverksanrop.
class UserActivity : AppCompatActivity() {
// View via XML-layout
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 och DataBinding — moderna verktyg som minskar kopplingen mellan Controller och View. ViewBinding genererar en klass med direkta referenser till View från XML, vilket eliminerar findViewById. DataBinding lägger till möjligheten att binda data med UI i XML-markering via @{user.name}. DataBinding — ett steg mot MVVM, eftersom det gör det möjligt att överföra data från Model till View utan kod i Activity. Google rekommenderar DataBinding för alla nya projekt.
Androids livscykel är mer komplex än iOS: Activity kan förstöras och återskapas vid skärmrotation, minnesbrist eller konfigurationsändring. I ren MVC innehåller kontrollern (Activity) logik som går förlorad vid förstörelse. Detta kräver att tillståndet sparas via onSaveInstanceState eller ViewModel från Jetpack, vilket går utanför ramen för ren MVC och för arkitekturen närmare MVVM.
Massive View Controller — en term som beskriver MVC:s huvudproblem inom mobilutveckling. Kontrollern i iOS och Android tar på sig för många ansvarsområden: bearbetning av indata, validering av data, nätverksinteraktion, navigering, cachning, animationer, hantering av livscykel. Som ett resultat växer kontrollern till 500–2000 rader kod, blir svår att läsa, testa och underhålla.
Orsaker till Massive View Controller — arkitekturen hos UIKit och Android Framework uppmuntrar placering av logik i kontrollern. Nätverksanrop, JSON-bearbetning, navigering — allt detta skrivs naturligt i Activity eller UIViewController eftersom de har tillgång till livscykeln och UI. Utvecklaren måste medvetet flytta ut logik till separata klasser (Service, Manager, Interactor), vilket kräver disciplin och förståelse för arkitekturprinciper.
| MVC-problem | Beskrivning | Lösning |
|---|---|---|
| Stark koppling | Controller känner till View och Model | MVVM — ViewModel känner inte till View |
| Svårt att testa | Controller är beroende av UIKit/Android | Flytta ut logik till tjänster |
| Livscykel | Tillstånd går förlorat vid rotation | ViewModel från Jetpack/SwiftUI |
| Brist på navigering | Controller hanterar övergångar | Coordinator-mönster, Router |
Testning av MVC — Model testas isolerat med enhetstester. Controller är svår att testa på grund av beroende av UIKit/UIFoundation. XCTest tillåter inte att skapa UIViewController utan visningsfönster. För Android löser ActivityTestRule och Robolectric delvis problemet, men testerna är långsamma. View testas vanligtvis inte med enhetstester — för UI används skärmbilds- och UI-tester (XCUITest, Espresso).
När MVC är motiverat — enkla skärmar med ett-två element (inloggningsskärm, profil, inställningar). Prototyper och MVP för att testa hypoteser — MVC skrivs snabbare utan extra lager. Projekt med liten kodbas upp till 10–15 skärmar. I komplexa projekt leder MVC till ackumulering av teknisk skuld och kräver omfaktorisering var 6–12:e månad.
MVC vs MVVM — den största skillnaden: i MVVM ersätts kontrollern av ViewModel som inte har någon referens till View. Data överförs via Observable (SwiftUI), LiveData/StateFlow (Android) eller Combine/RxSwift. ViewModel testas med enhetstester utan UI-beroenden. Apple rekommenderar MVVM med SwiftUI sedan 2019, Google — MVVM med LiveData/Flow som officiell arkitektur för Android. MVVM kräver mer kod för bindning, men förbättrar testbarheten avsevärt.
MVC vs MVP — i MVP (Model-View-Presenter) är Presenter ett testbart lager som tar emot View via ett gränssnitt. Till skillnad från MVC, där Controller direkt hanterar View via UIKit, är Presenter inte beroende av ramverket — det fungerar via abstraktionen ViewInterface. MVP var populärt inom Android-utveckling innan Jetpack kom och används i gamla projekt. Presenter lever längre än Activity och bevarar tillståndet vid skärmrotation.
MVC vs Clean Architecture — Clean Architecture lägger till lager Use Cases (Interactors), Entities, Gateways och Repository. MVC förblir i presentationslagret, men affärslogiken flyttas till domänlagret med Use Cases. Clean Architecture löser problemet med Massive View Controller radikalt — Controller innehåller endast anrop till Use Cases och uppdatering av View. Nackdelen är en betydande ökning av antalet klasser och filer, vilket är motiverat för projekt med 50+ skärmar.
// MVC i iOS: Controller innehåller allt
class OrderViewController: UIViewController {
func placeOrder() {
// Validering + nätverk + UI-uppdatering
guard Validation.isValid(total) else { return }
NetworkService.shared.submit(order) { [weak self] result in
self?.handleResult(result)
}
}
}
// MVVM: logik i ViewModel
class OrderViewModel: ObservableObject {
@Published var state: OrderState = .idle
func placeOrder() { /* affärslogik */ }
}
Val av arkitektur beror på teamstorlek, projekt och erforderlig testbarhet. För ett team på 1–2 utvecklare och ett projekt upp till 20 skärmar är MVVM lämpligt. För ett stort team på 5 utvecklare och ett projekt från 50 skärmar — Clean Architecture med modulär struktur. MVC förblir relevant för att förstå evolutionen av arkitekturer, för stöd av äldre projekt och för enkla skärmar i UIKit utan komplex affärslogik.
Vanliga frågor
Huvudproblemet är Massive View Controller. I iOS är UIViewController-kontrollern ansvarig för allt: bearbetning av indata, uppdatering av View, arbete med nätverk, navigering och livscykel. I Android utför Activity/Fragment liknande funktioner. Som ett resultat växer kontrollern till tusentals rader kod, blir svår att testa och underhålla, vilket bryter mot principen om enskilt ansvar.
I MVC uppdaterar kontrollern direkt View och bearbetar användarindata. I MVVM utförs kontrollerns roll av ViewModel som inte har någon referens till View — data överförs via bindningsmekanismer. MVVM testas bättre eftersom ViewModel inte är beroende av UIKit eller Android Framework. Apple rekommenderar MVVM med SwiftUI, Google — MVVM med Jetpack Compose.
Ja, MVC förblir ett fungerande mönster för enkla skärmar och prototyper. Apple rekommenderar MVC för UIKit-applikationer med enkla skärmar. För komplexa projekt med många skärmar, nätverksförfrågningar och cachning är det bättre att välja MVVM, VIPER eller Clean Architecture. Nybörjarutvecklare rekommenderas att bemästra MVC innan de studerar mer komplexa mönster.
Model testas isolerat — det är vanliga dataobjekt och affärslogik. Controller är svår att testa på grund av beroende av UIKit eller Android Framework. Det rekommenderas att flytta affärslogiken från kontrollern till separata tjänster eller interaktorer, som testas med enhetstester. View testas vanligtvis inte med enhetstester — för den används UI-tester och skärmbildstester.
På iOS — MVVM med SwiftUI och Combine, Apples standard sedan 2019. På Android — MVVM med LiveData eller StateFlow, officiellt rekommenderat av Google. För stora projekt med team från 5 utvecklare — Clean Architecture med VIPER på iOS eller Clean Architecture på Android med uppdelning i moduler efter funktioner. För äldre projekt med MVC — gradvis omfaktorisering med utflyttning av logik till separata tjänster.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också