- Published on
Repository patterni
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
10.2 darsda biznes logikasini viewdan view modelga ko'chirdingiz. Endi keyingi qavatga tushamiz: ma'lumot qayerdan keladi?
Hozir view model tarmoq so'rovlari yoki ma'lumot bazasiga bevosita murojaat qilishi mumkin. Bu yana ikkita muammo yaratadi: view model ikki turli ish qilyapti va Preview uchun real tarmoq kerak.
Repository patterni bu ikkala muammoni hal qiladi.
Kutubxonachi metafori: kitob so'raysiz — olasiz. Kutubxonachidan kitob javondan olindimi, boshqa kutubxonadan buyurtma berilganmi yoki raqamli arxivdan olindimi — bilmaysiz. Shunchaki so'radingiz va oldingiz. Repository xuddi shunday ishlaydi.
To'rt qadam
// 1-qadam: Protokol — view model faqat shu bilan gaplashadi
protocol KitobRepository {
func kitoblarniYukla() async throws -> [Kitob]
func saqlash(_ kitob: Kitob) async throws
}
// 2-qadam: Haqiqiy implementatsiya — tarmoqdan ma'lumot oladi
struct TarmoqKitobRepository: KitobRepository {
func kitoblarniYukla() async throws -> [Kitob] {
let url = URL(string: "https://api.example.com/kitoblar")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([Kitob].self, from: data)
}
func saqlash(_ kitob: Kitob) async throws {
// API ga POST
}
}
// 3-qadam: Mock implementatsiya — testlar va Preview uchun
struct MockKitobRepository: KitobRepository {
func kitoblarniYukla() async throws -> [Kitob] {
// Darhol, bashoratli ma'lumot — tarmoq kerak emas
[Kitob(sarlavha: "Swift dasturlash"), Kitob(sarlavha: "Dizayn patternlari")]
}
func saqlash(_ kitob: Kitob) async throws {
// Hech narsa — bu soxta
}
}
// 4-qadam: View modeli — protokolga bog'liq, aniq turga emas
@Observable
class KitobKorinishiModeli {
var kitoblar: [Kitob] = []
var yuklanmoqda = false
// any kalit so'zi — KitobRepository ga mos istalgan turni saqlaydi
private let repository: any KitobRepository
// Produksiyada standart haqiqiy, testda mock uzating — bu dependency injection
init(repository: any KitobRepository = TarmoqKitobRepository()) {
self.repository = repository
}
func kitoblarniYukla() async {
yuklanmoqda = true
do {
kitoblar = try await repository.kitoblarniYukla()
} catch {
// Xatoni bu yerda boshqaring
}
yuklanmoqda = false
}
}
| Qator | Vazifasi |
|---|---|
protocol KitobRepository | Interfeys — shartnoma. View modeli faqat shu haqida biladi. |
struct TarmoqKitobRepository: KitobRepository | Haqiqiy implementatsiya — real tarmoq so'rovlari qiladi. |
struct MockKitobRepository: KitobRepository | Test va Preview implementatsiyasi — darhol, hardcoded ma'lumot qaytaradi. |
private let repository: any KitobRepository | any — KitobRepository ga mos istalgan turni saqlaydi. View modeli qaysi biri muhim emas. |
init(repository: any KitobRepository = TarmoqKitobRepository()) | Produksiyada hech narsa uzatmang. Test uchun mock uzating. |
Repository variantlari
// Lokal saqlash repository — xuddi shu pattern, boshqa ma'lumot manbasi
struct LocalKitobRepository: KitobRepository {
let modelContext: ModelContext
func kitoblarniYukla() async throws -> [Kitob] {
let tavsif = FetchDescriptor<Kitob>()
return try modelContext.fetch(tavsif)
}
func saqlash(_ kitob: Kitob) async throws {
modelContext.insert(kitob)
try modelContext.save()
}
}
// View modeli o'zgarmaydi — faqat repository o'zgaradi
// Preview da mock inject qilish
#Preview {
// Mock — tarmoq yo'q, kutish yo'q, bashoratli ma'lumot
let model = KitobKorinishiModeli(repository: MockKitobRepository())
KitobRo'yxatiKorinishi(model: model)
}
// Xato holatini test qilish — haqiqiy muvaffaqiyatsiz server kerak emas
struct MuvaffaqiyatsizKitobRepository: KitobRepository {
func kitoblarniYukla() async throws -> [Kitob] {
throw URLError(.notConnectedToInternet)
}
func saqlash(_ kitob: Kitob) async throws { }
}
#Preview("Xato holati") {
KitobRo'yxatiKorinishi(model: KitobKorinishiModeli(repository: MuvaffaqiyatsizKitobRepository()))
}
Tezkor ma'lumotnoma
| Sintaksis | Vazifasi |
|---|---|
protocol Repo { func yukla() async throws -> [T] } | Repository interfeysi — barcha implementatsiyalar bajarishi kerak |
struct HaqiqiyRepo: Repo { } | Produksiya implementatsiyasi — haqiqiy ma'lumot manbasiga gaplashadi |
struct MockRepo: Repo { } | Test/Preview implementatsiyasi — tezkor, hardcoded ma'lumot |
private let repo: any Repo | Protokolga mos istalgan turni saqlaydi |
init(repo: any Repo = HaqiqiyRepo()) | Produksiyada standart — test uchun mock uzating |
🎯 Topshiriq: repository qo'shish
10.2 darsdan VazifaKorinishiModeli ni oling. Hozir u vazifalar massivini to'g'ridan-to'g'ri saqlaydi. VazifaRepository protokolini vazifalarniYukla() va vazifaQoshish(_ matn: String) metodlari bilan yarating. LocalVazifaRepository — xotira massivi bilan va MockVazifaRepository — uchta hardcoded vazifa bilan yozing. View modelini any VazifaRepository ga bog'lang. Preview Mock bilan ishlashini tasdiqlang.