Published on

SwiftUI Map App β€” ViewModel: @StateObject va @EnvironmentObject

Authors

ViewModel: @StateObject va @EnvironmentObject

Bu videoda MVVM arxitekturasining markaziy qismi β€” LocationsViewModel quriladi va barcha view-larga @EnvironmentObject orqali uzatiladi.


LocationsView yaratish

Views/ papkasida yangi SwiftUI View fayli yaratiladi β€” LocationsView.swift. Bu ilovaning asosiy ekrani bo'ladi.


LocationsViewModel β€” boshlang'ich versiya

Avval ViewModel-ni xuddi shu faylda qurib ko'ramiz, keyin alohida faylga ko'chiramiz.

import Foundation
import MapKit

class LocationsViewModel: ObservableObject {

    @Published var locations: [Location] = []

    init() {
        let locations = LocationsDataService.locations
        self.locations = locations
    }
}

Va LocationsView-da:

struct LocationsView: View {

    @StateObject private var vm = LocationsViewModel()

    var body: some View {
        List {
            ForEach(vm.locations) { location in
                Text(location.name)
            }
        }
    }
}

Bu boshlang'ich versiya β€” @StateObject bilan faqat shu view ichida ishlatiladi. Keyinroq @EnvironmentObject-ga o'tkaziladi.


Location-ni Identifiable-ga moslashtirish

ForEach bilan ishlaganda Swift har bir elementni farqlash uchun noyob identifikator talab qiladi. Buning uchun Location struct-i Identifiable protokoliga mos bo'lishi kerak:

// ❌ Tez, lekin noto'g'ri
let id: String = UUID().uuidString
// Har safar yaratilganda yangi id hosil bo'ladi β€”
// ikkita bir xil Location turli id-ga ega bo'ladi

To'g'ri yondashuv β€” id-ni mavjud ma'lumotlardan hisoblash:

// βœ… To'g'ri
struct Location: Identifiable {
    let name: String
    let cityName: String
    // ... boshqa maydonlar

    var id: String {
        name + cityName
    }
}

Nima uchun name + cityName?

  • Bir shahardan ikki xil joy β†’ nomlar farq qiladi β†’ id farq qiladi βœ…
  • Ikki shahardagi bir xil nomli joy β†’ shahar nomi farq qiladi β†’ id farq qiladi βœ…
  • To'liq bir xil joy β†’ id ham bir xil β†’ Swift ularni bir ob'ekt deb biladi βœ…

Haqiqiy ilovada bu id odatda backend ma'lumotlar bazasidagi unikal identifikator bo'ladi. Bu misolda ma'lumotlar bazasi yo'qligi uchun name + cityName kombinatsiyasi ishlatiladi.


@EnvironmentObject β€” ViewModel-ni butun ilovaga tarqatish

@StateObject bilan ViewModel faqat bitta view-da mavjud. Boshqa view-larga @Binding orqali uzatish kerak bo'ladi β€” bu katta loyihalarda chalkash bo'lib ketadi.

Yechim: ViewModel-ni ilova darajasida yaratib, @EnvironmentObject orqali barcha child view-larga tarqatish.

App.swift β€” ViewModel-ni muhitga qo'shish

@main
struct SwiftUIMapAppApp: App {

    @StateObject private var vm = LocationsViewModel()

    var body: some Scene {
        WindowGroup {
            LocationsView()
                .environmentObject(vm)
        }
    }
}

LocationsView β€” muhitdan olish

struct LocationsView: View {

    @EnvironmentObject private var vm: LocationsViewModel

    var body: some View {
        List {
            ForEach(vm.locations) { location in
                Text(location.name)
            }
        }
    }
}

Endi vm β€” yangi yaratilmaydi, muhitdan (environment) olinadi.

Preview uchun

Preview muhitda @EnvironmentObject mavjud bo'lmaydi β€” shuning uchun preview-ga alohida qo'shish kerak:

struct LocationsView_Previews: PreviewProvider {
    static var previews: some View {
        LocationsView()
            .environmentObject(LocationsViewModel())
    }
}

ViewModel-ni alohida faylga ko'chirish

LocationsViewModel kodi ViewModels/ papkasidagi yangi Swift File β€” LocationsViewModel.swift-ga ko'chiriladi:

import Foundation
import MapKit

class LocationsViewModel: ObservableObject {

    @Published var locations: [Location] = []

    init() {
        self.locations = LocationsDataService.locations
    }
}

@StateObject va @EnvironmentObject β€” taqqoslash

@StateObject@EnvironmentObject
Yaratilish joyiShu view ichidaApp yoki ota view-da
Kirish imkoniFaqat shu viewBarcha child view-lar
Uzatish usuli@Binding kerakAvtomatik, muhit orqali
Qachon ishlatiladiLokal holatGlobal, umumiy holat

Video oxiridagi loyiha holati

SwiftUIMapApp/
β”œβ”€β”€ Models/
β”‚   └── Location.swift          ← Identifiable qo'shildi
β”œβ”€β”€ Views/
β”‚   └── LocationsView.swift     ← @EnvironmentObject ishlatadi
β”œβ”€β”€ ViewModels/
β”‚   └── LocationsViewModel.swift ← yangi fayl
β”œβ”€β”€ DataServices/
β”‚   └── LocationsDataService.swift
└── SwiftUIMapAppApp.swift      ← vm yaratiladi va muhitga uzatiladi

Ilovani build qilib LocationsView-da barcha joy nomlari ko'rinishi kerak β€” bu ViewModel to'g'ri ulanganligi belgisi.


Keyingi videoda LocationsView-ning asosiy UI qismi quriladi β€” xarita, pinlar va joy kartasi.

Buy mea coffee