Published on

MVC — Apple ning standart arxitekturasi

Authors

Arxitektura nima va nima uchun kerak?

Tasavvur qiling: siz uy quryapsiz. Arxitektorsiz qursangiz — boshida tez, lekin 2-qavat qo'shmoqchi bo'lsangiz hamma narsa qulab tushadi. Arxitektura pattern — ilovangizning "loyihasi". U qoidalar beradi: qaysi kod qayerda turadi, qaysi qism qaysi qism bilan gaplashadi.

Nega muhim:

  • 6 oydan keyin o'z kodingizni tushunasiz
  • Yangi funksiya qo'shish oson — boshqa joylarni buzmasdan
  • Xato topish tez — qayerda qidirish kerakligini bilasiz
  • Jamoa ishlashi qulay — har kim o'z qismida ishlaydi
  • Test yozish mumkin — UI siz logikani tekshirish

MVC (Model-View-Controller) — eng qadimiy va keng tarqalgan pattern. Apple UIKit ni shu asosda qurgan. 1979-yilda Trygve Reenskaug tomonidan yaratilgan — deyarli 50 yillik tajriba!

MVC ning uchta qismi

// ═══════════════════════════════════════════════════════════════
//  MODEL — ma'lumotlar va biznes logikasi
//
//  Model — ilovangizning "miyasi". U:
//  ✅ Ma'lumotlarni saqlaydi (struct, class)
//  ✅ Biznes qoidalarini amalga oshiradi
//  ❌ UI haqida HECH NARSA bilmaydi
//  ❌ View yoki Controller ni import qilmaydi
//
//  Misol: Vazifa — faqat sarlavha va holat saqlaydi
//  Qayerda ko'rsatilishini bilmaydi va bilishi shart emas
// ═══════════════════════════════════════════════════════════════
struct Vazifa: Identifiable {
    let id = UUID()         // Har vazifaning noyob identifikatori
    var sarlavha: String    // Vazifa matni
    var bajarildi: Bool = false  // Bajarilganmi? Default: yo'q

    // Biznes logika — Model ichida
    // Bu qoida Controller dan mustaqil ishlaydi
    var muhimmi: Bool {
        sarlavha.contains("❗️")  // Undov belgisi bor = muhim
    }
}


// ═══════════════════════════════════════════════════════════════
//  CONTROLLER — Model va View orasida vositachi (ko'prik)
//
//  Controller — "dirigyor". U:
//  ✅ Foydalanuvchi amallarini qabul qiladi (View dan)
//  ✅ Model ni yangilaydi (biznes logika chaqiradi)
//  ✅ View ni qayta chizishga buyruq beradi
//  ⚠️ UIKit da bu UIViewController — haddan tashqari katta bo'lib ketadi!
//
//  SwiftUI da Controller ning roli kamaydi:
//  @Published + ObservableObject — View o'zi Model ni kuzatadi
//  Controller ning "vositachilik" roli tabiiy ravishda yo'qoladi
// ═══════════════════════════════════════════════════════════════
class VazifaController: ObservableObject {
    // @Published — bu property o'zgarganda
    // barcha kuzatuvchi View lar avtomatik qayta chiziladi
    // Bu Combine framework ning Publisher mexanizmi
    @Published var vazifalar: [Vazifa] = []

    // ── YARATISH ──
    // View "Qo'shish" tugmasini bosganda bu chaqiriladi
    // Controller Model yaratadi va ro'yxatga qo'shadi
    func qoshish(sarlavha: String) {
        // Validatsiya — bo'sh matn qo'shilmasin
        let tozalangan = sarlavha.trimmingCharacters(in: .whitespaces)
        guard !tozalangan.isEmpty else { return }

        // Yangi Model ob'ekt yaratish
        let yangi = Vazifa(sarlavha: tozalangan)
        // Ro'yxatga qo'shish — @Published o'zgaradi — View yangilanadi
        vazifalar.append(yangi)
    }

    // ── YANGILASH ──
    // Foydalanuvchi checkmark bosganda bu chaqiriladi
    // Controller Model ning holatini o'zgartiradi
    func almashish(id: UUID) {
        // firstIndex — ID bo'yicha vazifani topish
        guard let index = vazifalar.firstIndex(where: { $0.id == id }) else {
            return // Topilmasa — hech narsa qilmaymiz
        }
        // toggle() — true ↔ false almashish
        vazifalar[index].bajarildi.toggle()
        // @Published o'zgardi — View avtomatik yangilanadi
    }

    // ── O'CHIRISH ──
    func ochirish(id: UUID) {
        // removeAll — shartga mos barcha elementni o'chirish
        vazifalar.removeAll { $0.id == id }
    }

    // ── FILTRLASH ──
    // Computed property — har chaqirilganda hisoblanadi
    // Saqlanmaydi — vazifalar o'zgarganda avtomatik yangilanadi
    var bajarilmaganlar: [Vazifa] {
        vazifalar.filter { !$0.bajarildi }
        // filter — shartga mos elementlarni tanlaydi
        // !$0.bajarildi — bajarilMAGANlarni oladi
    }

    var bajarilganSoni: Int {
        vazifalar.filter(\.bajarildi).count
        // \.bajarildi — KeyPath qisqartmasi
        // { $0.bajarildi } bilan bir xil
    }
}


// ═══════════════════════════════════════════════════════════════
//  VIEW — foydalanuvchiga ko'rsatish
//
//  View — "yuz". U:
//  ✅ Ma'lumotni ekranda ko'rsatadi
//  ✅ Foydalanuvchi amallarini qabul qilib Controller ga uzatadi
//  ❌ Biznes logika yo'q — faqat UI
//  ❌ To'g'ridan-to'g'ri Model ni o'zgartirmaydi
//
//  SwiftUI da View = struct (value type)
//  body — har safar holat o'zgarganda qayta hisoblanadi
// ═══════════════════════════════════════════════════════════════
struct VazifaKorinishi: View {
    // @StateObject — Controller ni yaratadi va egalaydi
    // View qayta chizilganda Controller yo'qolmaydi
    // View lifecycle = Controller lifecycle
    @StateObject private var controller = VazifaController()

    // @State — faqat View ga tegishli vaqtinchalik holat
    // Controller ga aloqasi yo'q — faqat UI uchun
    @State private var yangiVazifa = ""

    var body: some View {
        NavigationStack {
            List {
                // ForEach — har vazifa uchun qator yaratish
                // controller.vazifalar — Controller dan ma'lumot olish
                ForEach(controller.vazifalar) { vazifa in
                    HStack {
                        // Checkmark ikonka — bajarildi/bajarilmadi
                        Image(systemName: vazifa.bajarildi
                            ? "checkmark.circle.fill"  // ✅ Bajarildi
                            : "circle")                 // ⭕ Bajarilmadi
                            .foregroundStyle(vazifa.bajarildi ? .green : .gray)
                            .onTapGesture {
                                // View → Controller → Model
                                // View o'zi Model ni o'zgartirmaydi!
                                // Controller ga "almashish" buyrug'i beradi
                                controller.almashish(id: vazifa.id)
                            }

                        Text(vazifa.sarlavha)
                            // strikethrough — bajarilgan vazifani chizib tashlash
                            .strikethrough(vazifa.bajarildi)
                            .foregroundStyle(vazifa.bajarildi ? .secondary : .primary)
                    }
                }
            }
            .toolbar {
                // Pastki panelda yangi vazifa kiritish
                ToolbarItem(placement: .bottomBar) {
                    HStack {
                        TextField("Yangi vazifa", text: $yangiVazifa)
                            .textFieldStyle(.roundedBorder)

                        Button("Qo'shish") {
                            // View → Controller → yangi Model yaratish
                            controller.qoshish(sarlavha: yangiVazifa)
                            yangiVazifa = "" // UI tozalash — bu View ning ishi
                        }
                        .disabled(yangiVazifa.trimmingCharacters(in: .whitespaces).isEmpty)
                    }
                }
            }
            .navigationTitle("Vazifalar (\(controller.bajarilganSoni) bajarildi)")
        }
    }
}

MVC diagrammasi — ma'lumot oqimi

MVC da ma'lumot qanday oqadi:

┌──────────────────────────────────────────────────────┐
│                                                      │
│   ┌──────────┐      ┌───────────────────┐            │
│   │  MODEL   │◄────►│   CONTROLLER      │            │
│   │          │      │                   │            │
│   │ • Vazifa │      │ • VazifaCtrl      │            │
│   │ • struct │      │ • ObservableObject││   │ • sof    │      │ • @Published      │            │
│   │   malumot│      │ • biznes logika   │            │
│   └──────────┘      └────────┬──────────┘            │
│                              │                       │
│                     @Published o'zgaradi              │
View avtomatik qayta chiziladi    │
│                              │                       │
│                              ▼                       │
│                     ┌───────────────────┐            │
│                     │      VIEW         │            │
│                     │                   │            │
│                     │ • SwiftUI struct  │            │
│                     │ • @StateObject    │            │
│                     │ • UI ko'rsatish   │            │
│                     │ • amal → Ctrl     │            │
│                     └───────────────────┘            │
│                                                      │
└──────────────────────────────────────────────────────┘

Qadam-baqadam oqim:
1. 👆 FoydalanuvchiView da tugma bosadi
2. 📤 ViewController ga funksiya chaqiradi
3. ⚙️  ControllerModel ni yaratadi/o'zgartiradi
4. 📢 Model o'zgardi → @Published signal beradi
5. 🔄 View → avtomatik qayta chiziladi (yangi holat bilan)

Massive View Controller — haqiqiy muammo

// ═══════════════════════════════════════════════════════════════
//  ❌ UIKIT DAGI "REAL" MVC
//  Bu — haqiqiy loyihalarda sodir bo'ladigan holat
//  Controller HAR NARSANI qiladi — bu "Massive View Controller"
// ═══════════════════════════════════════════════════════════════
class VazifaViewController: UIViewController,
    UITableViewDataSource,   // 📋 Jadval ma'lumotlari — 50+ qator
    UITableViewDelegate,     // 📋 Jadval hodisalari — 80+ qator
    UITextFieldDelegate,     // ⌨️ Matn kiritish — 30+ qator
    URLSessionDelegate,      // 🌐 Tarmoq so'rovlari — 100+ qator
    UISearchBarDelegate,     // 🔍 Qidiruv — 40+ qator
    UIScrollViewDelegate {   // 📜 Scroll hodisalari — 30+ qator

    // ── UI elementlar ──
    // var tableView: UITableView!
    // var searchBar: UISearchBar!
    // var loadingIndicator: UIActivityIndicatorView!
    // ... 50+ qator faqat UI sozlash

    // ── Tarmoq so'rovlari ──
    // func fetchTasks() { ... }
    // func uploadTask(_ task: Task) { ... }
    // func deleteTask(_ id: UUID) { ... }
    // ... 100+ qator tarmoq kodi

    // ── Ma'lumotlar bazasi ──
    // func saveToCoreData() { ... }
    // func loadFromCoreData() { ... }
    // ... 80+ qator bazakodi

    // ── Navigatsiya ──
    // func showDetail(_ task: Task) { ... }
    // func showSettings() { ... }
    // ... 60+ qator navigatsiya

    // ── Animatsiyalar ──
    // func animateCell(_ cell: UITableViewCell) { ... }
    // ... 40+ qator animatsiya

    // JAMI: 500-2000 QATOR BITTA FAYLDA 😱
    // Bu "Massive View Controller" = "MVC" ning asl muammosi
    //
    // Natijalari:
    // ❌ Kod o'qib bo'lmaydi — qaysi qism qayerda?
    // ❌ Test yozib bo'lmaydi — Controller UI ga bog'langan
    // ❌ Bir joyni o'zgartirish boshqa joyni buzadi
    // ❌ Yangi dasturchi tushunmaydi
    // ❌ Merge conflict har doim
}

MVC ning kuchi va zaifi

Jihat✅ Kuchli❌ Zaif
SoddalikTushunish oson, past kirish to'sig'iKatta loyihalarda tartibsizlik
TezlikPrototip yaratish tezTest yozish qiyin
Apple qo'llab-quvvatlashiUIKit rasmiy patterniSwiftUI da tabiiy emas
KengayishKichik ilovalar uchun yetarliController haddan tashqari o'sadi
Mas'uliyatAniq 3 qatlamAmalda Controller hamma ishni qiladi

MVC dan MVVM ga o'tish sababi

// ═══════════════════════════════════════════════════════════════
//  NEGA MVVM GA O'TDIK?
//
//  SwiftUI ning @State va @Published tizimi tufayli
//  Controller "vositachi" rolini yo'qotdi
// ═══════════════════════════════════════════════════════════════

// MVC da oqim (ko'p qadam):
// View → Controller → Model → Controller → View
//        ↑ Controller hamma narsani boshqaradi
//        ↑ View va Model bir-birini bilmaydi
//        ↑ Controller juda katta bo'lib ketadi

// SwiftUI da oqim (tabiiy):
// View ← @Published ← ViewModel/Model
//        ↑ View o'zi kuzatadi — Observable
//        ↑ Controller kerak emas!
//        ↑ Bu MVVM ning asosiy g'oyasi

// Xulosa:
// MVC → kichik loyihalar, prototip, o'rganish uchun yaxshi
// MVVM → SwiftUI bilan ishlaganda tabiiy va to'g'ri tanlov
// Keyingi darsda MVVM ni chuqur o'rganamiz!

🎯 Topshiriq: MVC ni tushunish

Yuqoridagi VazifaController ga quyidagi funksiyalarni qo'shing:

  1. filtrlash(faqatBajarilmagan: Bool) — foydalanuvchi faqat bajarilmagan vazifalarni ko'rishi uchun
  2. tartiblash() — vazifalarni alifbo tartibida saralash
  3. muhimVazifalar — faqat ❗️ belgili vazifalarni qaytaruvchi computed property

Controller qancha tez kattalashayotganini ko'ring — bu "Massive View Controller" muammosini his qilishga yordam beradi. Keyingi darsda MVVM bilan bir xil ilovani qanday toza yozishni ko'rasiz.

Buy mea coffee