- Published on
MVC — Apple ning standart arxitekturasi
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
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. 👆 Foydalanuvchi → View da tugma bosadi
2. 📤 View → Controller ga funksiya chaqiradi
3. ⚙️ Controller → Model 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 |
|---|---|---|
| Soddalik | Tushunish oson, past kirish to'sig'i | Katta loyihalarda tartibsizlik |
| Tezlik | Prototip yaratish tez | Test yozish qiyin |
| Apple qo'llab-quvvatlashi | UIKit rasmiy patterni | SwiftUI da tabiiy emas |
| Kengayish | Kichik ilovalar uchun yetarli | Controller haddan tashqari o'sadi |
| Mas'uliyat | Aniq 3 qatlam | Amalda 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:
filtrlash(faqatBajarilmagan: Bool)— foydalanuvchi faqat bajarilmagan vazifalarni ko'rishi uchuntartiblash()— vazifalarni alifbo tartibida saralashmuhimVazifalar— 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.