@StateObject SwiftUI dagi Property Wrapper bo'lib, ObservableObject misolasini to'g'ridan-to'g'ri view da yaratish va unga egalik qilish uchun xizmat qiladi. SwiftUI ob'ektning view hayot sikli davomida bir marta ishga tushirilishini va qayta renderlarda qayta yaratilmasligini kafolatlaydi. Apple Developer Documentation (2025) ga ko'ra, @StateObject ma'lumot manbasini yaratadigan ildiz view lar uchun tavsiya etiladi. @StateObject SwiftUI ierarxiyasida ObservableObject ga egalik qilish uchun to'g'ri tanlovdir.
Asosiy fikrlar
@StateObject SwiftUI 2.0 (iOS 14) da paydo bo'lgan, @ObservedObject va @State imkoniyatlarini birlashtiruvchi Property Wrapper dir. @ObservedObject kabi, ObservableObject dagi o'zgarishlarga obuna bo'ladi. @State kabi, ma'lumotlarning view strukturaning qayta ishga tushirilishidan omon qolishini kafolatlaydi. @StateObject ob'ektni view ekranda birinchi marta paydo bo'lganda bir marta yaratadi va uni SwiftUI heap ida saqlaydi.
@StateObject paydo bo'lishidan oldin, dasturchilar barcha ObservableObject lar uchun, shu jumladan view larda yaratilganlar uchun @ObservedObject dan foydalanardilar. Bu ota view yangilanganda view strukturasi qayta yaratilib, @ObservedObject misolasini ham olib ketishi sababli tez-tez ma'lumot yo'qotilishiga olib kelardi. @StateObject barqarorlik kafolatini qo'shib, bu muammoni hal qildi.
Asosiy qoida: @StateObject standart ishga tushirgichda (let model = ViewModel()) ob'ektni yaratadigan view da qo'llaniladi. Ushbu ob'ektni oladigan bola view lar @ObservedObject dan foydalanadi. Bunday bo'linish butun ierarxiyada yagona haqiqat manbaini kafolatlaydi.
SwiftUI @StateObject ning hayot siklini @State ga o'xshash saqlash menejeri orqali boshqaradi. View birinchi marta paydo bo'lganda, SwiftUI ob'ekt uchun xotira ajratadi va uni doimiy hududda saqlaydi. Qayta renderlarda (body chaqiruvi) ob'ekt qayta yaratilmaydi — mavjud misola ishlatiladi. Ob'ekt view ierarxiyada ekan, yashaydi.
View ierarxiyadan olib tashlanganda, SwiftUI @StateObject ni yo'q qiladi, deinit ni chaqiradi. View ierarxiyaga qayta qo'shilganda yangi misola yaratiladi. Buni loyihalashda hisobga olish muhim: view olib tashlashlari orasida ma'lumotlarni saqlash kerak bo'lsa, xizmat qatlami (singleton yoki DI) yoki @AppStorage dan foydalaning.
class TimerViewModel: ObservableObject {
@Published var seconds: Int = 0
private var timer: Timer?
func start() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.seconds += 1
}
}
deinit {
timer?.invalidate()
}
}
struct TimerView: View {
@StateObject var viewModel = TimerViewModel()
var body: some View {
Text("\(viewModel.seconds)s")
.onAppear { viewModel.start() }
}
}
Misolda, TimerViewModel @StateObject orqali yaratiladi va TimerView ekranda ekan yashaydi. Timer onAppear da ishga tushadi va deinit da to'xtaydi. Agar @ObservedObject ishlatilganda, har bir TimerView renderida sekundlari = 0 bo'lgan yangi TimerViewModel yaratiladi va timer hech qachon to'g'ri ishlamaydi. @StateObject viewModel ning yagona va barqaror ekanligini kafolatlaydi.
@StateObject va @ObservedObject o'rtasidagi tanlov ob'ektga kim egalik qilishiga bog'liq. Agar view ob'ektni yaratsa — @StateObject. Agar view tayyor ob'ektni olsa — @ObservedObject. Bu qoida shunchalik muhimki, Xcode ishga tushirgich orqali ob'ekt oladigan bola view da @StateObject ishlatilganda ogohlantirish chiqaradi.
| Vaziyat | Tavsiya etilgan wrapper |
|---|---|
| View ViewModel() orqali model yaratadi | @StateObject |
| View modelni otadan oladi | @ObservedObject |
| Model bitta view da ishlatiladi | @StateObject |
| Model Environment orqali uzatiladi | @EnvironmentObject |
| Model oldindan ko'rish uchun kerak | @ObservedObject + mock |
Amalda, loyiha boshida ko'pincha ildiz view da @StateObject va barcha bola view larda @ObservedObject ishlatiladi. Ilova o'sib borgan sari, ierarxiyani soddalashtirish uchun @StateObject ning bir qismi @EnvironmentObject bilan almashtirilishi mumkin. Biroq, @StateObject o'z mantiqiga ega modul ekranlar uchun eng yaxshi tanlov bo'lib qoladi.
Birinchi na'muna — MVVM @StateObject bilan. ViewModel ObservableObject sifatida view da @StateObject orqali yaratiladi. ViewModel @Published xususiyatlari va biznes mantiqini o'z ichiga oladi. View o'zgarishlarga obuna bo'ladi va interfeysni yangilaydi. Bunday yondashuv test qilinadigan izolyatsiyani ta'minlaydi: ViewModel ni to'g'ridan-to'g'ri misola yaratib, UI siz test qilish mumkin.
Ikkinchi na'muna — @StateObject bog'liqliklar bilan. Agar ViewModel xizmatlarni talab qilsa, parametrlar bilan ishga tushirishdan foydalaning. Masalan, @StateObject var viewModel = UserViewModel(api: APIClient.shared). Biroq ehtiyot bo'ling: parametrlar har bir body renderida hisoblanadi, lekin ob'ekt faqat bir marta yaratiladi. SwiftUI @StateObject ning keyingi ishga tushirilishlarini e'tiborsiz qoldiradi.
Uchinchi na'muna — ichma-ich @StateObject. SwiftUI da bitta view da bir nechta @StateObject bo'lishi mumkin, lekin bu kamdan-kam oqlanadi. Odatda bitta @StateObject view ning barcha ma'lumotlar to'plami uchun javobgardir. Agar mantiq juda murakkablashsa, uni bitta @StateObject ichida @ObservedObject xizmatlari kompozitsiyasiga bo'ling.
struct AppView: View {
@StateObject var router = NavigationRouter()
@StateObject var auth = AuthViewModel()
var body: some View {
ContentView()
.environmentObject(router)
.environmentObject(auth)
}
}
Misolda, AppView ikkita @StateObject yaratadi: navigatsiyani boshqarish uchun NavigationRouter va autentifikatsiya uchun AuthViewModel. Ikkala ob'ekt environmentObject orqali Environment ga kiritiladi. Har qanday bola view ularga ishga tushirish zanjiridan o'tmasdan @EnvironmentObject orqali kirishi mumkin.
@StateObject istalgan parametrlar bilan ishga tushirishni qo'llab-quvvatlaydi, lekin muhim xususiyat bilan: ishga tushirgich faqat bir marta chaqiriladi. Body ning qayta renderlarida parametrlarning yangi qiymati e'tiborga olinmaydi. Bu shuni anglatadiki, @State var id: Int = 5 ni @StateObject var vm = ViewModel(id: id) ga uzatsangiz, id o'zgarganda ViewModel yangi qiymatni olmaydi.
Bu muammoni hal qilish uchun sinxronizatsiya uchun onReceive yoki onAppear dan foydalaning. ViewModel ichida Combine orqali parametr o'zgarishlariga obuna bo'ling yoki view darajasida .onChange(of:) metodi orqali parametrlarni uzating. Muqobil — ob'ekt tashqi o'zgarishlarga dinamik reaksiya berishi kerak bo'lsa, @StateObject o'rniga @ObservedObject dan foydalaning.
struct DetailView: View {
let itemId: Int
@StateObject var viewModel = DetailViewModel()
var body: some View {
Text(viewModel.title)
.onAppear { viewModel.load(id: itemId) }
}
}
To'g'ri yondashuv: DetailView itemId ni let xususiyati sifatida oladi (struktura ishga tushirgichi orqali uzatiladi), @StateObject esa parametrsiz DetailViewModel yaratadi. onAppear da uzatilgan ID uchun ma'lumotlarni yuklaydigan load(id:) metodi chaqiriladi. Bu ViewModel @StateObject mexanizmi bilan yaratilganligini, lekin ma'lumotlar har view paydo bo'lganda joriy ID bilan yuklanishini kafolatlaydi.
Asosiy xato — bola view larda @StateObject ishlatish, ular ob'ektni otadan oladilar. Agar ParentView @StateObject model yaratsa va ChildView @StateObject var model: ModelType (standart parametr bilan) e'lon qilsa, ChildView o'z mustaqil misolasini yaratadi. Ota va bola ob'ektlari bog'liq bo'lmaydi va biridagi o'zgarishlar ikkinchisida aks etmaydi.
Ikkinchi xato — @StateObject ni List yoki ForEach da joylashtirish. Ro'yxatning har bir elementi o'z @StateObject ini yaratadi, bu ko'plab mustaqil misolalarga olib keladi. Ro'yxatlar uchun barcha elementlarga bitta ObservableObject ni @ObservedObject orqali uzatish yoki List ichida @State bilan Identifiable strukturalardan foydalanish to'g'ridir.
Uchinchi muammo — deinit tozalashning yo'qligi. @StateObject view ning butun hayot sikli davomida yashaydi. Agar ob'ekt taymerlar, Combine obunalari yoki tarmoq so'rovlarini yaratsa, deinit ularni bekor qilishi kerak. Aks holda xotira oqishlari va ekran yopilgandan keyin fon ishining davom etishi muqarrar. Har doim Combine Cancellable store yoki deinit da taymerlarni invalidate dan foydalaning.
Tez-tez so'raladigan savollar
@StateObject SwiftUI 2.0 da WWDC 2020 da iOS 14, macOS 11, watchOS 7 va tvOS 14 bilan birga qo'shilgan. Undan oldin @ObservedObject ObservableObject bilan ishlashning yagona usuli edi, bu tez-tez ma'lumot yo'qotish xatolariga olib kelardi.
Yo'q, @StateObject Optional turlarini qo'llab-quvvatlamaydi. Ob'ekt e'lon qilishda ishga tushirilishi kerak. Agar ixtiyoriy ob'ekt kerak bo'lsa, ixtiyoriy tur bilan @ObservedObject yoki @EnvironmentObject dan foydalaning.
ObservableObject ning ishga tushirgichiga va deinit iga print(#function) qo'shing. Qayta renderlarda init chaqirilmasa — @StateObject to'g'ri ishlaydi. Init har safar chaqirilsa — @ObservedObject ni @StateObject bilan almashtiring.
Ha, @StateObject UIHostingController orqali UIKit ga joylashtirilgan SwiftUI view larida ishlaydi. Ob'ektning hayot sikli UIViewController ga emas, SwiftUI view ga bog'langan. SwiftUI view almashtirilsa, @StateObject yo'q qilinadi.
Ajratilgan mas'uliyatli bir nechta kichik @StateObject. Bu test qilinishni, qayta foydalanishni va unumdorlikni yaxshilaydi — bir ob'ekt o'zgarganda interfeysning faqat obuna bo'lgan qismlari qayta chiziladi, butun view emas.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.