MVI — موبائل ایپس میں Model-View-Intent پیٹرن کو سمجھنا

مصنف: IT Sectr اشاعت: 2026-02-16 مطالعے کا وقت: 10 منٹ

MVI (Model-View-Intent) ایک ری ایکٹیو آرکیٹیکچرل پیٹرن ہے جو یک سمتی ڈیٹا فلو اور ناقابل تغیر حالت پر مبنی ہے۔ MVVM کے برعکس، جہاں ایک ViewModel کے متعدد StateFlows ہو سکتے ہیں، MVI ایک واحد حالت (State)، ناقابل تغیر ارادے (Intent) اور ایک خالص ریڈیوسر فنکشن (Reducer) کی وضاحت کرتا ہے۔ MVI کسی بھی وقت اسکرین کی حالت کی پیش گوئی کی ضمانت دیتا ہے۔ یہ پیٹرن Mosby اور Orbit لائبریریوں کے ذریعے Android کمیونٹی میں مقبول ہوا۔ مزید معلومات Arkadii Ivanov کے MVIKotlin میں۔

اہم نکات

  • MVI — Model (حالت)، View (نمائش)، Intent (صارف کا ارادہ) — ایک ری ایکٹیو سائیکل
  • Unidirectional data flow — ڈیٹا ایک سمت میں چلتا ہے: Intent → Reducer → State → View
  • Immutable State — اسکرین کی حالت ایک ناقابل تغیر آبجیکٹ ہے، ہر تبدیلی پر دوبارہ تخلیق ہوتی ہے
  • Reducer — ایک خالص فنکشن جو موجودہ حالت اور Intent لیتا ہے، نئی حالت لوٹاتا ہے
  • Side effects — ضمنی اثرات (نیٹ ورک، DB) Reducer سے الگ Middleware کے ذریعے سنبھالے جاتے ہیں

MVI کیا ہے: Model-View-Intent پیٹرن کا جوہر

MVI (Model-View-Intent) ایک ری ایکٹیو آرکیٹیکچرل پیٹرن ہے جو Redux اور Cycle.js کے اصولوں پر بنایا گیا ہے۔ Model ناقابل تغیر اسکرین حالت ہے، Intent صارف یا نظام کا ارادہ ہے، View حالت کو سبسکرائب کرتا ہے اور Intents بھیجتا ہے۔ ڈیٹا ایک سائیکل میں بہتا ہے: صارف View کے ساتھ تعامل کرتا ہے → View ایک Intent بناتا ہے → Intent Reducer کے ذریعے پروسیس ہوتا ہے → Reducer ایک نئی حالت بناتا ہے → View نئی حالت وصول کرتا ہے اور دوبارہ رینڈر کرتا ہے۔

MVI اور MVVM کے درمیان بنیادی فرق واحد سچائی کا ذریعہ (Single Source of Truth) ہے۔ MVVM میں، ایک ViewModel کے متعدد LiveData/StateFlow (userState، loadingState، errorState) ہو سکتے ہیں، جو عدم مطابقت کا باعث بنتا ہے: loading=true اور user=null ایک ساتھ۔ MVI میں، بالکل ایک sealed class/interface State ہے جو پوری اسکرین کی حالت بیان کرتا ہے۔ کسی بھی وقت، اسکرین کی حالت منفرد طور پر متعین ہوتی ہے — ڈیٹا پہلے سے لوڈ ہونے پر loading=true ہونا ناممکن ہے۔ IT Sectr میں، ہم پیچیدہ منطق والی اسکرینوں — آرڈر فارم، ملٹی اسٹیپ رجسٹریشن، مالیاتی اسکرینوں — کے لیے MVI استعمال کرتے ہیں جہاں حالت کی پیش گوئی اہم ہے۔

جزوMVI میں کردارمثال
Intentصارف یا نظام کا ارادہLoadUser, Refresh, SubmitForm
Stateناقابل تغیر اسکرین حالتsealed class UserState
Reducerخالص فنکشن: State + Intent → Statefun reduce(state, intent) -> state
Middlewareضمنی اثرات کا انتظامنیٹ ورک کی درخواست، DB تحریر

MVI سائیکل پانچ مراحل پر مشتمل ہے: 1) View ایک Intent بھیجتا ہے (مثلاً LoadUser(42))؛ 2) Middleware (EffectHandler) ایک ضمنی اثر انجام دیتا ہے — ایک نیٹ ورک کی درخواست؛ 3) نتیجہ نظام میں ایک نئے Intent کے طور پر واپس آتا ہے؛ 4) Reducer موجودہ حالت اور Intent لیتا ہے، ایک نئی حالت بناتا ہے؛ 5) View نئی حالت وصول کرتا ہے اور دوبارہ رینڈر کرتا ہے۔ ہر مرحلہ پیش گوئی کے قابل اور الگ تھلگ جانچنے کے قابل ہے۔

Android میں MVI: Kotlin میں Intent، Reducer، State

Android میں MVI Intent اور State کے لیے sealed کلاسز، MVI منطق کے ساتھ ViewModel، اور ری ایکٹیو رینڈرنگ کے لیے Jetpack Compose کا استعمال کرتے ہوئے نافذ کیا جاتا ہے۔ ViewModel View سے Intent وصول کرتا ہے، ضمنی اثرات Middleware کو سونپتا ہے، Reducer چلاتا ہے، اور StateFlow کے ذریعے نئی حالت شائع کرتا ہے۔ Jetpack Compose حالت بدلنے پر UI کو دوبارہ رینڈر کرتا ہے — MVI سائیکل کے لیے مثالی۔

kotlin
// Intent — صارف کے ارادے
sealed interface UserIntent {
    data class LoadUser(val userId: Int) : UserIntent
    data object Refresh : UserIntent
}

// State — واحد اسکرین حالت
sealed interface UserState {
    data object Idle : UserState
    data object Loading : UserState
    data class Success(val user: User) : UserState
    data class Error(val message: String) : UserState
}

// Reducer — خالص فنکشن
object UserReducer {
    fun reduce(state: UserState, intent: UserIntent): UserState = when (intent) {
        is UserIntent.LoadUser -> UserState.Loading
        is UserIntent.Refresh -> UserState.Loading
    }
}

// MVI کے ساتھ ViewModel
class UserViewModel(
    private val repository: UserRepository
) : ViewModel() {

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

    fun process(intent: UserIntent) {
        val newState = UserReducer.reduce(_state.value, intent)
        _state.value = newState
        when (intent) {
            is UserIntent.LoadUser -> loadUser(intent.userId)
            is UserIntent.Refresh -> loadUser(/* پچھلا ID */)
        }
    }

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

// View Intent بھیجتا ہے
fun UserScreen(viewModel: UserViewModel) {
    val state by viewModel.state.collectAsState()
    LaunchedEffect(Unit) { viewModel.process(UserIntent.LoadUser(42)) }
    when (state) {
        is UserState.Loading -> CircularProgressIndicator()
        is UserState.Success -> UserCard((state as UserState.Success).user)
        is UserState.Error -> ErrorView((state as UserState.Error).message)
        is UserState.Idle -> Text("Press to load")
    }
}

Middleware اور ضمنی اثرات — MVI میں، ایک خالص Reducer نیٹ ورک کی درخواستیں نہیں کر سکتا۔ Middleware (جسے EffectHandler یا Bootstrapper بھی کہا جاتا ہے) Intent کو پروسیس کرتا ہے، ضمنی اثر انجام دیتا ہے، اور سائیکل میں واپس ایک نیا Intent بھیجتا ہے۔ Orbit MVI اور MVIKotlin لائبریریاں قابل جانچ اثرات کے ساتھ بلٹ ان Middleware سپورٹ فراہم کرتی ہیں۔ Middleware کے بغیر، MVI اضافی Intent اور State ساخت کے ساتھ MVVM میں تبدیل ہو جاتا ہے۔

Arkadii Ivanov کا MVIKotlin Kotlin Multiplatform کے لیے سب سے مقبول MVI لائبریری ہے۔ یہ Android، iOS، ویب اور JVM کو سپورٹ کرتی ہے۔ یہ اجزاء فراہم کرتی ہے: Store (ViewModel)، Bootstrapper (ابتدائی اثرات)، Reducer، Middleware۔ اکتوبر 2025 تک، لائبریری نے GitHub پر 2.5K ستارے جمع کیے ہیں اور تجارتی منصوبوں میں استعمال ہو رہی ہے، جس میں بڑے روسی بینکوں کی ایپلی کیشنز شامل ہیں۔ IT Sectr میں، ہم مشترکہ کاروباری منطق کے ساتھ کراس پلیٹ فارم KMP پروجیکٹس کے لیے MVIKotlin استعمال کرتے ہیں۔

iOS میں MVI: Swift میں یک سمتی بہاؤ

iOS میں MVI Combine-ViewModel کے بغیر، Intent → State سائیکل کے ذریعے نافذ کیا جاتا ہے۔ View ایک closure کے ذریعے Intent بھیجتا ہے، Reducer ایک خالص فنکشن ہے، اور State ناقابل تغیر فیلڈز کے ساتھ ایک struct ہے۔ جب State بدلتا ہے تو SwiftUI View کو دوبارہ رینڈر کرتا ہے، اضافی @Published خصوصیات کے بغیر MVI سائیکل میں بالکل فٹ بیٹھتا ہے۔ iOS پر MVI خاص طور پر ان SwiftUI ڈویلپرز میں مقبول ہے جو Redux (JavaScript) سے منتقل ہوئے ہیں۔

swift
// State — ناقابل تغیر ڈھانچہ
struct UserState: Equatable {
    var user: User?
    var isLoading = false
    var errorMessage: String?
}

// Intent — ارادوں کے ساتھ enum
enum UserIntent {
    case loadUser(id: Int)
    case refresh
    case userLoaded(User)
    case loadFailed(Error)
}

// Reducer — خالص فنکشن
func userReducer(state: UserState, intent: UserIntent) -> UserState {
    var newState = state
    switch intent {
    case .loadUser, .refresh:
        newState.isLoading = true
        newState.errorMessage = nil
    case .userLoaded(let user):
        newState.isLoading = false
        newState.user = user
    case .loadFailed(let error):
        newState.isLoading = false
        newState.errorMessage = error.localizedDescription
    }
    return newState
}

// Store — حالت کا مالک ہے اور اثرات کا انتظام کرتا ہے
final class UserStore: ObservableObject {
    @Published private(set) var state = UserState()
    private let service: UserService

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

    func dispatch(_ intent: UserIntent) {
        // 1. Reducer حالت کو اپ ڈیٹ کرتا ہے
        state = userReducer(state: state, intent: intent)
        // 2. Side effects (اگر ضرورت ہو)
        switch intent {
        case .loadUser(let id), .refresh:
            service.fetchUser(id: id) { [weak self] result in
                switch result {
                case .success(let user):
                    self?.dispatch(.userLoaded(user))
                case .failure(let error):
                    self?.dispatch(.loadFailed(error))
                }
            }
        default: break
        }
    }
}

TCA (The Composable Architecture) Point-Free کی طرف سے iOS کے لیے سب سے مقبول MVI نفاذ ہے، جو SwiftUI اور Combine پر بنایا گیا ہے۔ TCA Store، Reducer، Effect اور Environment فراہم کرتا ہے۔ اکتوبر 2025 تک، GitHub پر اس کے ستارے 13K سے تجاوز کر گئے ہیں — iOS پر MVI کا حقیقی معیار ہے۔ TCA Starbucks ایپس، Airbnb (جزوی طور پر) اور بہت سے انڈی پروجیکٹس میں استعمال ہوتا ہے۔ کسٹم MVI کے برعکس، TCA جانچ، نیویگیشن اور ضمنی اثرات کو فوری طور پر حل کرتا ہے۔

iOS پر MVI بمقابلہ MVVM — TCA/MVI حالت کی پیش گوئی فراہم کرتا ہے لیکن زیادہ بائلر پلیٹ کوڈ (Reducer, State, Action) کی ضرورت ہوتی ہے۔ @Published کے ساتھ MVVM بنیادی اسکرینوں کے لیے آسان ہے۔ IT Sectr میں، ہم 80% اسکرینوں کے لیے MVVM اور 20% پیچیدہ اسکرینوں — مالی لین دین، ملٹی اسٹیپ فارم، ڈریگ اینڈ ڈراپ انٹرفیس — کے لیے MVI (TCA) استعمال کرتے ہیں، جہاں حالت کی غلطی صارف کو پیسے کھا سکتی ہے۔

MVI بمقابلہ MVVM: MVI کب انتخاب کریں

MVI اور MVVM ایک ہی مسئلہ حل کرتے ہیں — پریزنٹیشن پرت کو منظم کرنا — لیکن حالت کے انتظام کے مختلف طریقوں کے ساتھ۔ MVVM متعدد ری ایکٹیو ذرائع (LiveData, @Published) کی اجازت دیتا ہے، جو عدم مطابقت کا باعث بن سکتا ہے۔ MVI کسی بھی وقت بالکل ایک حالت کی ضمانت دیتا ہے، اسے زیادہ سخت اور پیش گوئی کے قابل بناتا ہے، لیکن کوڈ کی مقدار بڑھاتا ہے۔

معیارMVVMMVI
حالتمتعدد LiveData/StateFlowواحد sealed class State
ڈیٹا کا بہاؤدو سمتی (View → ViewModel, LiveData → View)یک سمتی (Intent → Reducer → State → View)
ضمنی اثراتبراہ راست ViewModel میںMiddleware/EffectHandler کے ذریعے
جانچViewModel کے یونٹ ٹیسٹReducer + Middleware کے یونٹ ٹیسٹ
بائلر پلیٹ کوڈکم سے کمReducer + State + Intent + Middleware

MVI کب انتخاب کریں — وہ اسکرینیں جہاں حالت سختی سے متعین ہونی چاہیے: مالیاتی کارروائیاں، شاپنگ کارٹ، ہر مرحلے پر توثیق کے ساتھ ملٹی اسٹیپ فارم۔ ان منظرناموں میں، حالت کی غلطی کی لاگت (مثال کے طور پر، دو LiveData کے درمیان دوڑ کی حالت کی وجہ سے ایک آئٹم کے بغیر کارٹ کل دکھانا) اضافی کوڈ کی لاگت سے زیادہ ہے۔ MVVM میں آپ ٹیم کے نظم و ضبط پر بھروسہ کرتے ہیں؛ MVI میں آپ آرکیٹیکچر پر بھروسہ کرتے ہیں۔

MVVM کب کافی ہے — 80% معیاری اسکرینیں: صارف کی فہرست، پروفائل، ترتیبات، خبروں کی فیڈ۔ یہاں، ایک واحد حالت ضرورت سے زیادہ ہے، اور اضافی MVI ساخت ترقی کو سست کرے گی۔ IT Sectr میں، اصول یہ ہے: اگر کسی اسکرین میں منتقلی (لوڈنگ → ڈیٹا → خرابی → دوبارہ کوشش → لوڈنگ → ڈیٹا) کے ساتھ 3+ ممکنہ حالتیں ہیں — MVI استعمال کریں۔ اگر کسی اسکرین میں 1-2 غیر متزامن آپریشن ہیں — MVVM استعمال کریں۔

MVI کے بہترین طریقے اور عام غلطیاں

Sealed State — بہترین عمل MVI میں۔ حالت کو مختلف حالتوں (Loading، Success(data)، Error(message)) کے ساتھ sealed class/interface کے طور پر بیان کیا جاتا ہے۔ یہ ضمانت دیتا ہے کہ View متضاد حالت میں نہیں آئے گی — loading=true ہونے پر ڈیٹا ظاہر نہیں کیا جا سکتا کیونکہ Loading اور Success مختلف کلاسیں ہیں۔ حالت سے متعلق تمام ڈیٹا sealed variant کے اندر رہتا ہے: Success میں صارف ہوتا ہے، Error میں خرابی کا پیغام ہوتا ہے۔

Reducer کو خالص فنکشن رہنا چاہیے — API، DB یا SharedPreferences کالز کے بغیر۔ ایک خالص فنکشن State اور Intent لیتا ہے اور State لوٹاتا ہے۔ ضمنی اثرات (نیٹ ورک، DB، نیویگیشن، ٹوسٹ) Middleware میں یا Reducer کو کال کرنے کے بعد Store.dispatch میں سنبھالے جاتے ہیں۔ اگر Reducer ضمنی اثرات سے آلودہ ہو جاتا ہے، MVI جانچ کی اہلیت اور پیش گوئی کھو دیتا ہے — آپ کو بغیر فوائد کے اضافی ساخت کے ساتھ MVVM ملتا ہے۔

عام غلطیاں — sealed class کے بجائے nullable فیلڈز والی data class کے طور پر State کا اعلان: data class UserState(val user: User?, val isLoading: Boolean, val error: String?)۔ یہ MVVM کے برابر ہے، MVI نہیں — View کو درستگی کے لیے فیلڈ کے مجموعے چیک کرنے چاہئیں۔ sealed طریقہ میں، غلط مجموعے (isLoading=true اور user!=null) قسم کی سطح پر ناممکن ہیں۔ دوسری غلطی کاروباری منطق کو Middleware میں رکھنے کے بجائے Intent (Intent.LoadUserBeforeXHours) میں رکھنا ہے۔

اکثر پوچھے گئے سوالات

MVI اور MVVM میں بنیادی فرق کیا ہے؟

MVI ایک واحد ناقابل تغیر sealed State کلاس اور Reducer کے ذریعے یک سمتی ڈیٹا بہاؤ استعمال کرتا ہے۔ MVVM دو سمتی بائنڈنگ کے ساتھ متعدد LiveData/StateFlow کی اجازت دیتا ہے۔ MVI قسم کی سطح پر حالت کی مستقل مزاجی کی ضمانت دیتا ہے — loading=true اور user=null کا ایک ساتھ ہونا ناممکن ہے۔ MVVM ڈویلپر کے نظم و ضبط پر منحصر ہے۔

Android کے لیے کون سی MVI لائبریریاں موجود ہیں؟

اہم: MVIKotlin (Arkadii Ivanov، 2.5K ستارے، Kotlin Multiplatform)، Orbit MVI (BabyJ، 1.3K ستارے)، Mobius (Spotify، Kotlin/Java)۔ MVIKotlin Kotlin کے لیے سب سے مقبول، Orbit سیکھنے میں سب سے آسان ہے۔ تینوں قابل جانچ Reducer اور Middleware کو سپورٹ کرتی ہیں۔ Jetpack Compose کے لیے، آپ sealed State + Reducer استعمال کرکے لائبریری کے بغیر سادہ MVI لکھ سکتے ہیں۔

کیا MVI کے لیے علیحدہ لائبریری ضروری ہے؟

نہیں — sealed Intent + sealed State + ViewModel + StateFlow انحصار کے بغیر کام کرنے والا MVI دیتے ہیں۔ لائبریریاں (MVIKotlin, Orbit, TCA) Middleware، ضمنی اثرات کی جانچ اور DI انضمام شامل کرتی ہیں۔ سادہ منصوبوں کے لیے، لائبریری کا وزن ناقابل جواز ہے۔ 20+ اسکرینوں والے پیچیدہ منصوبوں کے لیے، لائبریری منظم اثرات کے انتظام سے خود کو ادائیگی کرتی ہے۔

کیا MVI iOS کے لیے موزوں ہے یا یہ صرف Android کا پیٹرن ہے؟

MVI TCA (The Composable Architecture) — SwiftUI کمیونٹی کا سب سے مقبول آرکیٹیکچر — کے ذریعے iOS کے لیے بہترین کام کرتا ہے۔ TCA بنیادی طور پر MVI + Redux + Combine ہے۔ iOS پر، آپ ObservableObject اور ایک خالص reducer فنکشن استعمال کرکے TCA کے بغیر MVI لاگو کر سکتے ہیں۔ ناقابل تغیر State کے ساتھ SwiftUI MVI سائیکل میں بالکل فٹ بیٹھتا ہے۔

MVI کی جانچ کیسے کریں؟

Reducer کو خالص فنکشن کے طور پر یونٹ ٹیسٹ سے جانچا جاتا ہے: ابتدائی State سیٹ کریں، Intent بھیجیں، نتیجے میں آنے والے State کی جانچ کریں۔ Middleware کو ایک فرضی ذخیرہ سے جانچا جاتا ہے: تصدیق کریں کہ LoadUser کے بعد getUser کو کال کیا گیا تھا۔ ViewModel ٹیسٹ: Intent بھیجیں، StateFlow چیک کریں۔ MVI کا MVVM کے مقابلے میں جانچنا آسان ہے کیونکہ Reducer پوشیدہ انحصار کے بغیر ایک خالص فنکشن ہے۔

خلاصہ

  • MVI (Model-View-Intent) — یک سمتی بہاؤ اور واحد حالت کے ساتھ ایک ری ایکٹیو پیٹرن
  • Sealed State — قسم کی سطح پر مستقل مزاجی کی ضمانت دیتا ہے، غلط مجموعوں کو ختم کرتا ہے
  • Reducer — خالص فنکشن State + Intent → State، فرضی اشیاء کے بغیر قابل جانچ
  • Middleware — ضمنی اثرات (نیٹ ورک، DB، نیویگیشن) کے لیے ایک علیحدہ پرت
  • MVI vs MVVM — MVI زیادہ سخت اور پیش گوئی کے قابل، MVVM آسان اور تیز
  • Android — پیچیدہ اسکرینوں کے لیے MVIKotlin یا Orbit؛ سادہ کے لیے MVVM
  • iOS — TCA (The Composable Architecture) SwiftUI پر MVI کا معیار ہے

ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے

IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔

پروجیکٹ پر بحث کریں

مزید پڑھیں