MVVM: bu nədir, Model-View-ViewModel patterni mobil inkişafda

Müəllif: IT Sectr Dərc olunub: 2026-02-16 Oxuma vaxtı: 9 dəq

MVVM (Model-View-ViewModel) — ViewModel-in Presenter-i əvəz etdiyi və View ilə əlaqə üçün reaktiv mexanizmlərdən istifadə edən memarlıq patternidir: SwiftUI-də ObservableObject, Android-də LiveData/StateFlow. ViewModel-in View-ə istinadı yoxdur — məlumatlar abunə vasitəsilə ötürülür, bu da ViewContract interfeyslərinə ehtiyacı aradan qaldırır və testləri daha da asanlaşdırır. Apple 2019-cu ildən SwiftUI ilə MVVM-i, Google isə Jetpack ilə MVVM-i Android-in rəsmi memarlığı kimi tövsiyə edir. Ətraflı Android Architecture Guide-də.

Əsas

  • MVVM — Model (məlumatlar), View (interfeys), ViewModel (View-ə istinad olmadan vəziyyət və məntiq)
  • Reactive binding — LiveData, StateFlow, ObservableObject məlumat dəyişdikdə UI-ni avtomatik yeniləyir
  • ViewModel — ekranın fırlanmasından sağ çıxır və Android SDK/UIKit-dən asılı deyil, unit-testlərlə test edilir
  • Android Jetpack — ViewModel, LiveData, DataBinding — Google-dan MVVM üçün rəsmi stack
  • SwiftUI + Combine — iOS-da @Published və @ObservedObject ilə MVVM-in yerli tətbiqi

MVVM nədir: Model-View-ViewModel patterninin mahiyyəti

MVVM (Model-View-ViewModel) — 2005-ci ildə John Gossman tərəfindən Microsoft-un Windows Presentation Foundation (WPF) üçün təsvir edilmiş memarlıq patternidir. ViewModel — ekranın vəziyyətini və biznes məntiqini ehtiva edən, lakin View-ə istinadı olmayan mərkəzi komponentdir. Məlumatlar reaktiv bağlama mexanizmləri vasitəsilə ötürülür: View ViewModel-in dəyişikliklərinə abunə olur və məlumatlar dəyişdikdə avtomatik yenidən çəkilir.

MVVM-nin MVP-dən əsas fərqi — ViewContract-in olmaması. MVP-də Presenter view.showUser(data) metodlarını çağırır, yəni Presenter aktiv şəkildə məlumatları View-ə “ötürür”. MVVM-də View özü məlumatları ViewModel-dən abunə vasitəsilə “cəkir”: ViewModel abunəçisinin olub-olmadığını bilmir. Bu, ayrılmış View problemini aradan qaldırır — əgər Activity fırlanma zamanı məhv olarsa, ViewModel işə davam edir, yeni Activity isə sadəcə aktual məlumatlara abunə olur. IT Sectr-də 2020-ci ildən bütün yeni layihələrdə MVVM istifadə edirik — kod daha proqnozlaşdırıla bilən, testlər daha sabit oldu.

KomponentMəsuliyyətPlatforma
ModelMəlumatlar, biznes məntiqi, repozitorilərAndroid/iOS
ViewGöstərmə, ViewModel-ə abunəActivity/Composable, UIView/SwiftUI View
ViewModelEkranın vəziyyəti, məntiq, naviqasiyaViewModel (Jetpack), ObservableObject

Reaktiv bağlama — MVVM-in təməli. Android-də LiveData (Jetpack-in hissəsi) müşahidə olunan məlumat anbarıdır. Activity observe() vasitəsilə abunə olur: viewModel.user.observe(this) { user -> binding.name.text = user.name }. user dəyişdikdə bütün abunəçilər avtomatik olaraq yeni dəyər alır. iOS-da SwiftUI ViewModel-də @Published xassələrindən istifadə edir — dəyişikliklər avtomatik olaraq View-i yenidən çəkir. Bu, MVP-də tələb olunan əl ilə showUser/hideLoading çağırışlarını aradan qaldırır.

Android-də MVVM: ViewModel, LiveData və StateFlow

Jetpack-dən ViewModel — Google-dan MVVM-in tətbiqi üçün rəsmi komponent. ViewModel ekranın fırlanmasından sağ çıxır: konfiqurasiya dəyişdikdə Activity məhv olur və yenidən yaradılır, ViewModel isə yaddaşda qalır. Activity-nin yeni nümunəsi ViewModelProvider vasitəsilə eyni ViewModel-i alır. ViewModel-in Activity-yə, Context-ə və ya View-ə istinadları yoxdur — o, təmizdir və Robolectric olmadan unit-testlərlə test edilir.

kotlin
// ViewModel StateFlow ilə — MVVM-in müasir tətbiqi
class UserViewModel(
    private val repository: UserRepository
) : ViewModel() {

    private val _state = MutableStateFlow<UserState>(UserState.Loading)
    val state: StateFlow<UserState> = _state.asStateFlow()

    fun loadUser(userId: Int) {
        viewModelScope.launch {
            _state.value = UserState.Loading
            repository.getUser(userId)
                .onSuccess { user ->
                    _state.value = UserState.Success(user)
                }
                .onFailure { e ->
                    _state.value = UserState.Error(e.message ?: "Unknown")
                }
        }
    }
}

sealed interface UserState {
    data object Loading : UserState
    data class Success(val user: User) : UserState
    data class Error(val message: String) : UserState
}

// View (Activity) state-ə abunə olur
class UserActivity : AppCompatActivity() {
    private val viewModel: UserViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewModel.state.onEach { state ->
            when (state) {
                is UserState.Loading -> /* yükləməni göstər */
                is UserState.Success -> /* məlumatları göstər */
                is UserState.Error -> /* xətanı göstər */
            }
        }.launchIn(lifecycleScope)
        viewModel.loadUser(42)
    }
}

LiveData vs StateFlow — LiveData (2017) — Activity lifecycle-i üçün optimallaşdırılmış ilk Jetpack reaktiv komponenti: onStop-da avtomatik abunədən çıxma. StateFlow (2021) — lifecycle-ə bağlı olmayan, lakin lifecycleScope vasitəsilə əl ilə abunədən çıxma tələb edən Kotlin Flow tətbiqi. StateFlow coroutines, concat, map və LiveData-da olmayan digər Flow operatorlarını dəstəkləyir. IT Sectr-də bütün yeni ViewModel-lər üçün StateFlow istifadə edirik — o, daha qısa, daha güclüdür və korutinlərlə daha yaxşı inteqrasiya olunur.

DataBinding və ViewBinding — DataBinding ViewModel-i XML ilə @{viewModel.user.name} vasitəsilə birbaşa layoutda birləşdirir, Activity-də kodu aradan qaldırır. ViewBinding View-ə giriş üçün tip təhlükəsiz sinif yaradır. Google sadə layihələr üçün ViewBinding, mürəkkəb məlumat bağlaması olan layihələr üçün DataBinding tövsiyə edir. Jetpack Compose-da DataBinding lazım deyil — @Composable funksiyaları State dəyişdikdə avtomatik yenidən çəkilir.

iOS-da MVVM: ObservableObject və SwiftUI

iOS-da MVVM Combine-dən ObservableObject vasitəsilə tətbiq olunur. ViewModel — ObservableObject-dən miras alan sinifdir, @Published sahələri ilə. SwiftUI View @ObservedObject və ya @StateObject vasitəsilə ViewModel-ə abunə olur. @Published xassəsi dəyişdikdə SwiftUI bu xassədən asılı olan View-i avtomatik yenidən çəkir. Apple SwiftUI-ni 2019-cu ildə WWDC-də Combine ilə birlikdə təqdim etdi — bu andan MVVM iOS üçün rəsmi olaraq tövsiyə olunan pattern oldu.

swift
import SwiftUI
import Combine

// ViewModel — @Published sahələri olan ObservableObject
final class UserViewModel: ObservableObject {
    @Published private(set) var state: UserState = .loading
    private let service: UserService

    init(service: UserService) {
        self.service = service
    }

    func loadUser(id: Int) {
        state = .loading
        service.fetchUser(id: id) { [weak self] result in
            guard let self else { return }
            switch result {
            case .success(let user):
                self.state = .success(user)
            case .failure(let error):
                self.state = .error(error.localizedDescription)
            }
        }
    }
}

enum UserState {
    case loading
    case success(User)
    case error(String)
}

// SwiftUI View — ViewModel-ə abunə olur
struct UserView: View {
    @StateObject private var viewModel: UserViewModel

    var body: some View {
        switch viewModel.state {
        case .loading:
            ProgressView()
        case .success(let user):
            VStack {
                Text(user.name).font(.title)
                Text(user.email).font(.body)
            }
        case .error(let message):
            Text(message).foregroundColor(.red)
        }
    }
}

@StateObject vs @ObservedObject — @StateObject ViewModel yaradır və onun həyat dövrünü idarə edir (View-in ömrü boyu bir dəfə). @ObservedObject — ViewModel xaricdə yaradılır və View-ə ötürülür. WWDC 2022 yaratmaq üçün @StateObject və ViewModel-i Views arasında ötürmək üçün @ObservedObject tövsiyə edir. iOS 17-də (2023) @Observable peyda oldu — abunəni avtomatlaşdıran və @Published annotasiyalarını aradan qaldıran makro. @Observable — Combine-in təkamülüdür, iOS inkişafını Kotlin Flow reaktivliyinə yaxınlaşdırır.

UIKit + MVVM — UIKit-də (SwiftUI olmadan) layihələr üçün MVVM Combine və @Published vasitəsilə UIViewController-də sink() ilə abunə olaraq tətbiq olunur. ViewModel eynidir, View — @Published-ə abunə olan UIViewController. Combine iOS 13-dən (2019) etibarən mövcuddur və sistemə daxildir — əlavə asılılıq tələb etmir. Apple Developer Survey (2025) məlumatına görə, iOS layihələrinin 45%-i hətta UIKit-də Combine istifadə edir, 35%-i SwiftUI + Combine istifadə edir, 20%-i — RxSwift (legacy).

MVVM ilə MVP-nin müqayisəsi: üstünlüklər və çatışmazlıqlar

MVVM MVP-dən üstündür üç əsas aspektdə: ViewContract interfeyslərinin olmaması, abunələrin avtomatik idarə edilməsi və ekranın fırlanmasından sağ çıxma. MVP-də hər ekran ViewContract interfeysi + Presenter sinfi + onStart/onStop-da abunə/abunədən çıxma tələb edir. MVVM-də yalnız ViewModel yaradılır — Activity-də abunə observe() vasitəsilə əl ilə detach() olmadan həyata keçirilir.

KriteriyaMVPMVVM
ViewContract interfeysləri1 ekranaLazım deyil
Abunə idarəçiliyiƏl ilə attach/detachAvtomatik (lifecycle-aware)
Ekranın fırlanmasıRetain-fragmentViewModel sağ çıxır
Test etməMock ViewContractAsılılıqları olmayan təmiz sinif
ReaktivlikPresenter-də callback-lərLiveData/StateFlow/Combine

MVVM-in çatışmazlıqları — reaktiv zəncirlərin debug edilməsinin mürəkkəbliyi və yanlış abunə zamanı yaddaş sızması riski. LiveData lifecycle-təhlükəsizliyi problemini həll edir, StateFlow lifecycleScope tələb edir, Combine — AnyCancellable ilə sink. MVP-də bütün çağırışlar aşkardır (view.showUser), MVVM-də məlumatlar reaktiv axın vasitəsilə gəlir — izləmə subscribe closure-ında debug breakpointləri tələb edir. Çoxsaylı StateFlow olan böyük ViewModel-lərdə View müəyyən Flow-a abunə deyilsə, UI yenilənməsini qaçırmaq olar.

MVP nə vaxt daha yaxşıdır — minimum Android versiyası API 21-dən (Android 5) aşağı olan layihələrdə, Jetpack ViewModel AndroidX olmadan əlçatan deyil, və Combine olmadan təmiz UIKit-də (iOS 12 və aşağı) layihələrdə. Bütün kod bazası artıq MVP-də olan legacy layihələr üçün MVVM-ə tam keçid həmişə əsaslandırılmır — 3 ayda 100 ekranı yenidən yazmaqdansa, tədricən məntiqi xidmətlərə çıxarmaqla MVP-ni saxlamaq daha ucuzdur.

Android və iOS-da ViewModel-in test edilməsi

ViewModel platforma asılılıqları olmadan unit-testlərlə test edilir — bu MVVM-in lehinə əsas arqumentdir. Android-də ViewModel Activity, Context və ya View ehtiva etmir — bütün asılılıqlar (Repository, UseCase) konstruktor vasitəsilə ötürülür və mock obyektləri ilə əvəz olunur. iOS-da ObservableObject tətbiqi işə salmadan XCTest vasitəsilə test edilir, bu da testlərin sabitliyini və sürətini təmin edir.

kotlin
// MockK ilə Android ViewModel-in unit-testi
class UserViewModelTest {

    private val repository = mockk<UserRepository>()
    private val viewModel = UserViewModel(repository)

    @Test
    fun loadUser_success_updatesState() = runTest {
        val user = User(1, "John", "john@test.com")
        coEvery { repository.getUser(1) } returns Result.success(user)

        viewModel.loadUser(1)

        assertEquals(UserState.Success(user), viewModel.state.value)
    }

    @Test
    fun loadUser_error_updatesErrorState() = runTest {
        val error = RuntimeException("Network error")
        coEvery { repository.getUser(1) } returns Result.failure(error)

        viewModel.loadUser(1)

        val state = viewModel.state.value
        assertTrue(state is UserState.Error)
        assertEquals("Network error", (state as UserState.Error).message)
    }
}

iOS ViewModel analoji şəkildə test edilir: mock UserService yeridirik, loadUser çağırırıq, vəziyyəti XCTestExpectation vasitəsilə yoxlayırıq. Combine Publisher XCTestCase vasitəsilə wait(for: expectations, timeout: 1.0) ilə test edilir. UserState strukturu — associated values olan enum — əməliyyatdan sonra ekranın dəqiq vəziyyətini yoxlamağa imkan verir.

Kod əhatəsi IT Sectr-in MVVM-də layihələrində ViewModel və Repository üçün 75–90% təşkil edir. ViewModel unit-testlərlə, Repository test məlumat bazası ilə inteqrasiya testləri ilə əhatə olunur. SwiftUI və Jetpack Compose-da View kritik ssenarilər üçün UI testləri (XCUITest, Compose Test) ilə test edilir. Qalan UI snapshot testləri (Snapshot Testing) ilə yoxlanılır — bu UI testlərindən daha sürətlidir və göstərmənin düzgünlüyünə 95% əminlik verir.

Tez-tez verilən suallar

MVVM və MVP arasında əsas fərq nədir?

MVVM-də ViewModel-in View-ə istinadı yoxdur — məlumatlar reaktiv mexanizmlər (LiveData, StateFlow, @Published) vasitəsilə ötürülür. MVP-də Presenter birbaşa ViewContract interfeysi vasitəsilə View metodlarını çağırır. MVVM ViewContract və əl ilə attach/detach-i aradan qaldırır, lakin reaktiv axınları başa düşməyi tələb edir. ViewModel Android-də ekranın fırlanmasından sağ çıxır, Presenter retain-fragment tələb edir.

Android-də MVVM üçün hansı kitabxanalar lazımdır?

Minimum dəst: lifecycle-viewmodel-ktx (ViewModel), lifecycle-livedata-ktx və ya kotlinx-coroutines-core (StateFlow). İnjeksiya üçün — Hilt və ya Koin. Asinxron əməliyyatlar üçün — Kotlin Coroutines. Mürəkkəb məlumat bağlaması üçün — DataBinding. Jetpack Compose-da (Google tərəfindən 2022-dən tövsiyə olunur) compose-runtime və lifecycle-viewmodel-compose kifayətdir.

Niyə Apple iOS üçün MVVM tövsiyə edir?

SwiftUI (2019) reaktiv memarlıq üçün layihələndirilib: @State və @Published məlumat dəyişdikdə View-i avtomatik yenidən çəkir. MVVM SwiftUI-ə təbii uyğunluqdur: View — @ViewBuilder, ViewModel — ObservableObject. Apple MVVM-i yeganə pattern kimi təlqin etmir, lakin 2019-cu ildən bütün tədris materialları ViewModel + SwiftUI istifadə edir. UIKit üçün Apple MVC və ya Coordinator tövsiyə edir.

ViewModel-də yaddaş sızmalarından necə qaçınmaq olar?

Android: viewModelScope ViewModel təmizlənərkən korutinləri avtomatik ləğv edir. iOS: Combine-dən AnyCancellable onu saxlayan obyekt azad edilərkən avtomatik abunədən çıxır. SwiftUI @StateObject həyat dövrünü avtomatik idarə edir. Əsas qaydalar: ViewModel-də View/Context istinadları saxlamamaq, təmizləmə zamanı uzunmüddətli əməliyyatları ləğv etmək, closure-larda weak self istifadə etmək.

Android üçün LiveData yoxsa StateFlow seçmək?

StateFlow — müasir seçimdir. LiveData daha sadə və lifecycle-təhlükəsizdir, lakin StateFlow daha güclüdür: korutinlərlə işləyir, flatMap, combine, filter dəstəkləyir, @Nullable annotasiyası tələb etmir. LiveData-nın üstün olduğu yeganə ssenari — StateFlow-un (Kotlin Flow-API) əlçatan olmadığı Java kodu ilə işləməkdir. Google Kotlin-də yeni layihələr üçün StateFlow tövsiyə edir.

Nəticə

  • MVVM (Model-View-ViewModel) — ViewModel-in View-ə istinadı olmayan reaktiv pattern
  • ViewModel — ekranın fırlanmasından sağ çıxır, unit-testlərlə test edilir, UI-dən asılı deyil
  • Android — ViewModel + StateFlow + Kotlin Coroutines — Google-dan müasir stack
  • iOS — ObservableObject + @Published + SwiftUI — MVVM-in yerli tətbiqi
  • MVVM vs MVP — MVVM ViewContract və əl ilə attach/detach-i aradan qaldırır
  • Test etmə — ViewModel platforma asılılıqları olmadan unit-testlərlə əhatə olunur
  • Tövsiyə — MVVM yeni layihələr üçün; MVP legacy dəstəyi üçün

Açar təslim mobil tətbiq hazırlayacağıq

IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.

Layihəni müzakirə et

Həm də oxuyun