- Published on
@Observable va reference turlari bilan @State
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
Hozirgacha siz boshqargan holatlar (state) kichik va oddiy edi β hisoblagich, toggle yoki matn maydoni. Ammo haqiqiy ilovalarda real ma'lumotlar mavjud: vazifalar ro'yxati, foydalanuvchi profili yoki o'nlab elementlarga ega savatcha. Bularning barchasini view ichidagi @State xususiyatlariga tiqishtirish kodni tezda chalkashtirib yuboradi. Yechim β ma'lumotlaringizni alohida sinfga (class) ko'chirish va SwiftUI-ni o'sha sinfni kuzatishga majbur qilishdir.
Avvalgi (@State va @Binding) darslarida siz holatga to'g'ridan-to'g'ri view ichida egalik qildingiz. Bu mahalliy UI holati uchun juda mos keladi β masalan, ekran ochilganmi yoki yo'qmi, foydalanuvchi maydonga nima yozayotgani va hokazo. Ammo ilovangizning haqiqiy ma'lumotlar modelini ifodalovchi har qanday narsa view'dan tashqarida, aniq vazifalarga ega o'z sinfida yashashi kerak. Bu real ilovalar yaratish sari qo'yilgan katta qadamdir.
Ushbu darsning oxirida siz kuzatiladigan ma'lumotlar modelini yaratish uchun @Observable makrosidan (iOS 17+) qanday foydalanishni, view ichida ushbu modelning nusxasini saqlash uchun @State-dan qanday foydalanishni hamda mavjud kodlarda uchraydigan eski @ObservableObject va @StateObject patternlarini qanday tanib olishni bilib olasiz.
Swift-da yangimisiz? Ushbu darsda sinflar (classes) β Swift dasturlash tilining asosiy tushunchasi bilan tanishamiz. Agar sinf nimaligini yoki uning struct'dan qanday farq qilishini bilmasangiz, mustahkam poydevor uchun Swift bo'limidagi darslar seriyasini ko'rib chiqishingizni maslahat beramiz. Sinf va struct farqini yaxshi tushunish juda muhim.
Holatni model sinfiga ko'chirish (lifting State)
Mana o'sha model va hisoblagich view misoli:
| Kod / Satr | Vazifasi |
|---|---|
@Observable class CounterModel | @Observable makrosi sinfni jihozlaydi (instrument qiladi), shunda SwiftUI qaysi xususiyatlar o'qilayotganini kuzatib boradi va faqat o'zgargan xususiyatlarga bog'liq bo'lgan view'larni qayta chizadi. |
var count = 0 (@Observable ichida) | Bu yerda hech qanday property wrapper kerak emas β @Observable barcha saqlanadigan xususiyatlar uchun kuzatishni avtomatik ravishda boshqaradi. Bu uni eski yondashuvlardan ko'ra toza qiladi. |
@State private var model = CounterModel() | View model nusxasini saqlash uchun @State-dan foydalanadi. SwiftUI buni kuzatiladigan obyekt (observable object) ekanligini biladi va kuzatishni avtomatik ravishda sozlaydi. |
model.increment() | Model ustida metodni chaqirish count qiymatini o'zgartiradi. SwiftUI o'zgarishni aniqlaydi (@Observable tufayli) va view'ning count-ni o'qigan qismlarini qayta chizadi. |
@Observable patternlari (Patterns)
@Observable (zamonaviy, iOS 17+)
@Observable
class UserProfile {
var name = "Chris"
var isPremium = false
}
struct ProfileView: View {
@State private var profile = UserProfile()
var body: some View {
Text("Hello, \(profile.name)")
}
}
@Observable yordamida har bir saqlanadigan xususiyat avtomatik ravishda kuzatiladi. SwiftUI faqat o'zgargan xususiyatni haqiqatda o'qigan view'larnigina qayta chizadi β bu eski yondashuvga qaraganda ancha samaralidir.
@ObservableObject (eski pattern)
// Eski yondashuv β sinf ObservableObject protokoliga mos kelishi kerak
class UserProfile: ObservableObject {
// @Published o'zgarganda qayta chizishni boshlaydigan har bir xususiyatni belgilaydi
@Published var name = "Chris"
@Published var isPremium = false
}
struct ProfileView: View {
// @StateObject obyektni yaratadi va unga egalik qiladi
@StateObject private var profile = UserProfile()
var body: some View {
Text("Hello, \(profile.name)")
}
}
Siz ushbu patternga darsliklarda va iOS 16 yoki undan eski versiyalarga mo'ljallangan loyihalarda tez-tez duch kelasiz. Konseptlar bir xil β shunchaki qo'lda ko'proq yozish kerak. @Published xususiyati @Observable avtomatik qiladigan ishni bajaradi, @StateObject esa sinflar uchun @State muqobilidir.
Modelni bolalar view'lariga o'tkazish (passing a model)
@Observable
class CartModel {
var items: [String] = []
func addItem(_ item: String) {
items.append(item)
}
}
struct ShopView: View {
@State private var cart = CartModel()
var body: some View {
VStack {
// Ikkala bolaga ham bitta cart modelini o'tkazamiz β ular bir xil nusxani baham ko'rishadi
ProductListView(cart: cart)
CartSummaryView(cart: cart)
}
}
}
struct ProductListView: View {
// Bola view-da @Observable uchun hech qanday wrapper kerak emas β shunchaki oddiy xususiyat
var cart: CartModel
var body: some View {
Button("Add Item") { cart.addItem("Widget") }
}
}
Sinflar reference type (ko'rsatkich turi) bo'lganligi sababli, ProductListView ham, CartSummaryView ham bir xil CartModel nusxasiga ishora oladi. Biror bola element qo'shganda, boshqa bola o'zgarishni avtomatik ravishda ko'radi. Hech qanday binding kerak emas β ular bitta obyektni baham ko'rishmoqda.
iOS versiyasi eslatmasi:
@ObservableiOS 17+ talab qiladi. Eski iOS versiyalarini qo'llab-quvvatlash uchun: sinfda@ObservableObject, har bir kuzatiladigan xususiyatda@Published, view-da esa@Stateo'rniga@StateObjectishlating. Konsept bir xil β shunchaki yozilishi murakkabroq.
Tezkor ma'lumotnoma
| Sintaksis / Pattern | Vazifasi |
|---|---|
@Observable class MyModel | Barcha saqlanadigan xususiyatlarni kuzatiladigan qiladi β o'zgarish sodir bo'lganda SwiftUI tegishli view-larni yangilaydi |
@State var model = MyModel() | View ichida observable obyektni ushlab turadi β SwiftUI uning nusxasini yaratadi va unga egalik qiladi |
ObservableObject (eski) | @Observable-ga protokolga asoslangan eski muqobil β har bir xususiyatga @Published talab qiladi |
@Published var x (eski) | Qiymat o'zgarganda qayta chizishni ishga tushiruvchi xususiyat belgisi |
@StateObject (eski) | ObservableObject protokoliga mos keluvchi obyektlar uchun @State-ning eski muqobili |
Topshiriq: model bilan to-do ro'yxati
TaskModel nomli @Observable sinf yarating, unda var tasks: [String] = [] xususiyati va addTask(_ task: String) metodi bo'lsin. TaskListView view'ida ushbu modelni @State sifatida saqlang. Foydalanuvchi yangi vazifani yozishi uchun @State private var newTask = "" o'zgaruvchisiga bog'langan TextField-dan foydalaning. Yangi vazifani qo'shadigan va kiritish maydonini tozalaydigan tugma yarating. Vazifalarni List yordamida ekranga chiqaring. Har safar yangi vazifa qo'shilganda ro'yxat jonli ravishda yangilanishi kerak.
Maslahat: Ro'yxatni chizish uchun
List(model.tasks, id: \.self) { task in Text(task) }patternidan foydalaning.