Published on

SwiftUI-da EnvironmentObject — global holda ma'lumot ulashish

Authors

Bu video avvalgi — @StateObject va @ObservedObject videosining davomi. Agar u videoni ko'rmagan bo'lsangiz, avval uni ko'rib keliing.

Bu videoda biz @EnvironmentObject ni o'rganamiz. U @StateObject va @ObservedObject bilan bir xil ishlaydi, lekin katta farqi bor: ViewModel-ni ekrandan ekranga qo'lda uzatmasdan, muhitga qo'yib, barcha ekranlardan avtomatik olish mumkin.


Muammo — ViewModel-ni zanjir bo'ylab uzatish

Avvalgi videoda ViewModel-ni shunday uzatganmiz:

// 1-ekran — StateObject bilan yaratish
@StateObject var viewModel = EnvironmentViewModel()

// 2-ekranga uzatish
DetailView(viewModel: viewModel)

// 2-ekran — ObservedObject bilan qabul qilish
@ObservedObject var viewModel: EnvironmentViewModel

// 3-ekranga uzatish
FinalView(viewModel: viewModel)

// 3-ekran — ObservedObject bilan qabul qilish
@ObservedObject var viewModel: EnvironmentViewModel

Bu ishlaydi, lekin 5, 10, 20 ta ekran bo'lsa? Har bir ekranda @ObservedObject yozib, init-da qabul qilish juda charchattiradi. Bundan tashqari, 2-ekran ViewModel-ni faqat 3-ekranga uzatish uchun oladi — o'zi ishlatmaydi!


ViewModel yaratish

class EnvironmentViewModel: ObservableObject {

    @Published var dataArray: [String] = []

    init() {
        getData()
    }

    func getData() {
        self.dataArray.append(contentsOf: [
            "iPhone",
            "iPad",
            "iMac",
            "Apple Watch",
        ])
    }
}

1-usul: @StateObject va @ObservedObject (avvalgi video)

// 1-ekran
struct EnvironmentObjectBootcamp: View {
    @StateObject var viewModel = EnvironmentViewModel()

    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.dataArray, id: \.self) { item in
                    NavigationLink(item) {
                        // ViewModel-ni 2-ekranga uzatish shart
                        DetailView(selectedItem: item, viewModel: viewModel)
                    }
                }
            }
            .navigationTitle("iOS qurilmalar")
        }
    }
}

// 2-ekran — ViewModel oladi, lekin ishlatmaydi
struct DetailView: View {
    let selectedItem: String
    @ObservedObject var viewModel: EnvironmentViewModel  // faqat 3-ekranga uzatish uchun

    var body: some View {
        ZStack {
            Color.orange.ignoresSafeArea()
            NavigationLink {
                // 3-ekranga uzatish shart
                FinalView(viewModel: viewModel)
            } label: {
                Text(selectedItem)
                    .font(.headline)
                    .foregroundColor(.orange)
                    .padding()
                    .padding(.horizontal)
                    .background(Color.white.cornerRadius(30))
            }
        }
    }
}

// 3-ekran
struct FinalView: View {
    @ObservedObject var viewModel: EnvironmentViewModel

    var body: some View {
        ZStack {
            LinearGradient(
                colors: [Color.blue, Color.blue.opacity(0.7)],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            ).ignoresSafeArea()

            ScrollView {
                VStack(spacing: 20) {
                    ForEach(viewModel.dataArray, id: \.self) { item in
                        Text(item)
                            .font(.largeTitle)
                            .foregroundColor(.white)
                    }
                }
            }
        }
    }
}

Bu ishlaydi, lekin 2-ekran ViewModel-ni o'zi ishlatmaydi — faqat 3-ekranga uzatish uchun olgan.


2-usul: @EnvironmentObject (yaxshiroq yechim)

ViewModel-ni muhitga qo'yish — barcha ekranlar avtomatik oladi, uzatish shart emas:

// 1-ekran — ViewModel-ni muhitga qo'yish
struct EnvironmentObjectBootcamp: View {
    @StateObject var viewModel = EnvironmentViewModel()

    var body: some View {
        NavigationView {
            List {
                ForEach(viewModel.dataArray, id: \.self) { item in
                    NavigationLink(item) {
                        // viewModel uzatilmaydi — muhitda mavjud
                        DetailView(selectedItem: item)
                    }
                }
            }
            .navigationTitle("iOS qurilmalar")
        }
        // ViewModel-ni muhitga qo'yish
        .environmentObject(viewModel)
    }
}

// 2-ekran — ViewModel kerak emas, uzatmaydi
struct DetailView: View {
    let selectedItem: String
    // @ObservedObject yo'q — ViewModel-ni muhitdan olamiz

    var body: some View {
        ZStack {
            Color.orange.ignoresSafeArea()
            NavigationLink {
                // viewModel uzatilmaydi
                FinalView()
            } label: {
                Text(selectedItem)
                    .font(.headline)
                    .foregroundColor(.orange)
                    .padding()
                    .padding(.horizontal)
                    .background(Color.white.cornerRadius(30))
            }
        }
    }
}

// 3-ekran — ViewModel-ni muhitdan olish
struct FinalView: View {
    // @EnvironmentObject — muhitdan avtomatik olish
    @EnvironmentObject var viewModel: EnvironmentViewModel

    var body: some View {
        ZStack {
            LinearGradient(
                colors: [Color.blue, Color.blue.opacity(0.7)],
                startPoint: .topLeading,
                endPoint: .bottomTrailing
            ).ignoresSafeArea()

            ScrollView {
                VStack(spacing: 20) {
                    ForEach(viewModel.dataArray, id: \.self) { item in
                        Text(item)
                            .font(.largeTitle)
                            .foregroundColor(.white)
                    }
                }
            }
        }
    }
}

Qanday ishlaydi?

1-ekran: .environmentObject(viewModel) ← muhitga qo'yildi

NavigationLink

2-ekran: ViewModel kerak emas — muhitda bor, lekin ishlatilmaydi
         Hech narsa uzatilmaydi

NavigationLink

3-ekran: @EnvironmentObject var viewModel ← muhitdan olindi
         Avtomatik — hech narsa uzatilmagan

ViewModel bir joyda yaratildi, bir joyda muhitga qo'yildi. Barcha pastki ekranlar undan xohlagan vaqtda olishi mumkin.


⚠️ Muhim ogohlantirish

// Agar muhitda EnvironmentViewModel bo'lmasa — ilova crash bo'ladi!
@EnvironmentObject var viewModel: EnvironmentViewModel

// Shuning uchun Preview-da ham muhitni sozlash kerak
struct FinalView_Previews: PreviewProvider {
    static var previews: some View {
        FinalView()
            .environmentObject(EnvironmentViewModel()) // ← majburiy
    }
}

@EnvironmentObject ishlatgan har bir View-ning Preview-ida .environmentObject(...) qo'shmasangiz, preview crash bo'ladi.


Uchta property wrapper taqqoslov

Qayerda yaratiladiQanday olinadiQachon ishlatish
@StateObjectBirinchi View-daViewModel-ni birinchi marta yaratishda
@ObservedObjectBoshqa View-dan uzatiladiinit parametri orqali1-2 ta ekranga uzatishda
@EnvironmentObjectMuhitda (environmentObject)AvtomatikKo'p ekranlarda bir ViewModel kerak bo'lganda

Qachon EnvironmentObject ishlatish kerak?

// ✅ EnvironmentObject tavsiya etiladi:
// — 3+ ta ekran bir xil ViewModel kerak bo'lganda
// — Oraliq ekranlar ViewModel-ni ishlatmasa ham uzatishi kerak bo'lganda
// — Login holati, mavzu (dark/light) kabi global ma'lumotlar uchun

// ❌ EnvironmentObject ortiqcha bo'ladi:
// — Faqat 1-2 ta ekran bir ViewModel ishlatsa
//   → bu holda @StateObject + @ObservedObject yaxshiroq
// — Juda ko'p EnvironmentObject qo'shish ilovani sekinlashtiradi
//   va kodni chalkashtirib yuboradi

Xulosa

// Yaratish — bir marta, birinchi View-da
@StateObject var viewModel = EnvironmentViewModel()

// Muhitga qo'yish — barcha pastki ekranlar uchun
.environmentObject(viewModel)

// Olish — istalgan pastki ekranda, uzatmasdan
@EnvironmentObject var viewModel: EnvironmentViewModel

@EnvironmentObject — ilova bo'ylab ulashish kerak bo'lgan ma'lumotlar uchun ideal. Lekin ehtiyotkorlik bilan ishlating: faqat haqiqatan ham ko'p ekranlarda kerak bo'lgan ViewModel-larni muhitga qo'ying.

Rahmat, men Nick, bu Swiftful Thinking va keyingi videoda ko'rishguncha!

Buy mea coffee