@StateObject SwiftUI में ObservableObject इंस्टेंस को सीधे view में बनाने और उसका स्वामित्व रखने के लिए एक Property Wrapper है। SwiftUI गारंटी देता है कि ऑब्जेक्ट व्यू के जीवनचक्र में एक बार इनिशियलाइज़ होता है और बार-बार रेंडर होने पर पुनः निर्मित नहीं होता। Apple Developer Documentation (2025) के अनुसार, @StateObject रूट व्यूज़ के लिए अनुशंसित है जो डेटा स्रोत बनाते हैं। @StateObject SwiftUI पदानुक्रम में ObservableObject के स्वामित्व के लिए सही विकल्प है।
मुख्य बातें
@StateObject एक Property Wrapper है जो SwiftUI 2.0 (iOS 14) में पेश किया गया, जो @ObservedObject और @State की क्षमताओं को जोड़ता है। @ObservedObject की तरह, यह ObservableObject में बदलावों की सदस्यता लेता है। @State की तरह, यह गारंटी देता है कि डेटा व्यू संरचना के बार-बार इनिशियलाइज़ेशन से बचा रहता है। @StateObject ऑब्जेक्ट को एक बार तब बनाता है जब व्यू पहली बार स्क्रीन पर आता है और इसे SwiftUI के हीप में संग्रहीत करता है।
@StateObject से पहले, डेवलपर्स सभी ObservableObjects के लिए @ObservedObject का उपयोग करते थे, जिनमें व्यू में बनाए गए ऑब्जेक्ट भी शामिल थे। इससे बार-बार डेटा हानि होती थी जब पैरेंट व्यू अपडेट होता था, जिससे व्यू संरचना पुनः निर्मित होती थी और @ObservedObject इंस्टेंस अपने साथ ले जाती थी। @StateObject ने स्थिरता गारंटी जोड़कर इस समस्या को हल किया।
मुख्य नियम: @StateObject उस व्यू में उपयोग होता है जो डिफ़ॉल्ट इनिशियलाइज़र (let model = ViewModel()) में ऑब्जेक्ट बनाता है। चाइल्ड व्यू जो यह ऑब्जेक्ट प्राप्त करते हैं, @ObservedObject का उपयोग करते हैं। यह पृथक्करण पूरे पदानुक्रम में सत्य का एकल स्रोत सुनिश्चित करता है।
SwiftUI @StateObject के जीवनचक्र को @State के समान स्टोरेज मैनेजर के माध्यम से प्रबंधित करता है। जब व्यू पहली बार प्रकट होता है, SwiftUI ऑब्जेक्ट के लिए मेमोरी आवंटित करता है और इसे एक स्थायी क्षेत्र में संग्रहीत करता है। बाद के रेंडर (body कॉल) पर, ऑब्जेक्ट पुनः निर्मित नहीं होता—मौजूदा इंस्टेंस का उपयोग होता है। ऑब्जेक्ट तब तक जीवित रहता है जब तक व्यू पदानुक्रम में है।
जब व्यू पदानुक्रम से हटा दिया जाता है, SwiftUI @StateObject को नष्ट कर देता है, deinit को कॉल करता है। जब व्यू वापस पदानुक्रम में जोड़ा जाता है, तो एक नया इंस्टेंस बनाया जाता है। डिज़ाइन करते समय यह महत्वपूर्ण है: यदि आपको व्यू हटाने के बीच डेटा संरक्षित करने की आवश्यकता है, तो सेवा लेयर (सिंगलटन या DI) या @AppStorage का उपयोग करें।
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() }
}
}
उदाहरण में, TimerViewModel @StateObject के माध्यम से बनाया जाता है और तब तक जीवित रहता है जब तक TimerView स्क्रीन पर है। टाइमर onAppear में शुरू होता है और deinit में रुकता है। यदि @ObservedObject का उपयोग किया जाता, तो TimerView के प्रत्येक रेंडर पर seconds = 0 के साथ एक नया TimerViewModel बनता, और टाइमर कभी सही ढंग से काम नहीं करता। @StateObject गारंटी देता है कि viewModel अद्वितीय और स्थिर है।
@StateObject और @ObservedObject के बीच चुनाव इस पर निर्भर करता है कि ऑब्जेक्ट का मालिक कौन है। यदि व्यू ऑब्जेक्ट बनाता है—@StateObject। यदि व्यू को तैयार ऑब्जेक्ट मिलता है—@ObservedObject। यह नियम इतना महत्वपूर्ण है कि Xcode एक चेतावनी देता है जब @StateObject का उपयोग चाइल्ड व्यू में किया जाता है जो इनिशियलाइज़र के माध्यम से ऑब्जेक्ट प्राप्त करता है।
| स्थिति | अनुशंसित Wrapper |
|---|---|
| व्यू ViewModel() के माध्यम से मॉडल बनाता है | @StateObject |
| व्यू मॉडल को पैरेंट से प्राप्त करता है | @ObservedObject |
| मॉडल एक व्यू में उपयोग होता है | @StateObject |
| मॉडल Environment के माध्यम से पास किया जाता है | @EnvironmentObject |
| प्रीव्यू के लिए मॉडल आवश्यक है | @ObservedObject + mock |
व्यवहार में, परियोजना की शुरुआत में, @StateObject का उपयोग अक्सर रूट व्यू में और @ObservedObject का सभी चाइल्ड व्यू में किया जाता है। जैसे-जैसे एप्लिकेशन बढ़ता है, कुछ @StateObject इंस्टेंस को @EnvironmentObject से बदला जा सकता है। हालाँकि, @StateObject अपने स्वयं के तर्क वाली मॉड्यूलर स्क्रीन के लिए सबसे अच्छा विकल्प बना हुआ है।
पहला पैटर्न—@StateObject के साथ MVVM। ObservableObject के रूप में ViewModel @StateObject के माध्यम से व्यू में बनाया जाता है। ViewModel में @Published गुण और व्यावसायिक तर्क होते हैं। व्यू बदलावों की सदस्यता लेता है और इंटरफ़ेस अपडेट करता है। यह दृष्टिकोण परीक्षण योग्य अलगाव प्रदान करता है: ViewModel का सीधे इंस्टेंस बनाकर UI के बिना परीक्षण किया जा सकता है।
दूसरा पैटर्न—निर्भरताओं के साथ @StateObject। यदि ViewModel को सेवाओं की आवश्यकता है, तो पैरामीटर के साथ इनिशियलाइज़ेशन का उपयोग करें। उदाहरण के लिए, @StateObject var viewModel = UserViewModel(api: APIClient.shared)। हालाँकि, सावधान रहें: पैरामीटर प्रत्येक body रेंडर पर गणना किए जाते हैं, लेकिन ऑब्जेक्ट केवल एक बार बनता है। SwiftUI @StateObject के बाद के इनिशियलाइज़ेशन को अनदेखा करता है।
तीसरा पैटर्न—नेस्टेड @StateObject। SwiftUI में, एक व्यू में कई @StateObject हो सकते हैं, लेकिन यह शायद ही कभी उचित होता है। आमतौर पर एक @StateObject व्यू के संपूर्ण डेटा सेट को संभालता है। यदि तर्क बहुत जटिल हो जाता है, तो इसे एक @StateObject के अंदर @ObservedObject सेवाओं की संरचना में विभाजित करें।
struct AppView: View {
@StateObject var router = NavigationRouter()
@StateObject var auth = AuthViewModel()
var body: some View {
ContentView()
.environmentObject(router)
.environmentObject(auth)
}
}
उदाहरण में, AppView दो @StateObject बनाता है: NavigationRouter नेविगेशन प्रबंधन के लिए और AuthViewModel प्रमाणीकरण के लिए। दोनों ऑब्जेक्ट environmentObject के माध्यम से Environment में इंजेक्ट किए जाते हैं। कोई भी चाइल्ड व्यू इनिशियलाइज़र श्रृंखला से गुज़रे बिना @EnvironmentObject के माध्यम से उन तक पहुँच सकता है।
@StateObject किसी भी पैरामीटर के साथ इनिशियलाइज़ेशन का समर्थन करता है, लेकिन एक महत्वपूर्ण शर्त के साथ: इनिशियलाइज़र केवल एक बार कॉल होता है। बाद के body रेंडर पर, पैरामीटर में नए मान अनदेखा किए जाते हैं। इसका मतलब है कि यदि आप @State var id: Int = 5 को @StateObject var vm = ViewModel(id: id) में पास करते हैं, जब id बदलता है, ViewModel को नया मान नहीं मिलेगा।
इस समस्या को हल करने के लिए, सिंक्रनाइज़ेशन के लिए onReceive या onAppear का उपयोग करें। Combine के माध्यम से ViewModel के अंदर पैरामीटर बदलावों की सदस्यता लें या व्यू स्तर पर .onChange(of:) विधि के माध्यम से पैरामीटर पास करें। एक विकल्प @StateObject के बजाय @ObservedObject का उपयोग करना है यदि ऑब्जेक्ट को बाहरी बदलावों पर गतिशील रूप से प्रतिक्रिया देनी चाहिए।
struct DetailView: View {
let itemId: Int
@StateObject var viewModel = DetailViewModel()
var body: some View {
Text(viewModel.title)
.onAppear { viewModel.load(id: itemId) }
}
}
सही दृष्टिकोण: DetailView itemId को let गुण के रूप में प्राप्त करता है (संरचना के इनिशियलाइज़र के माध्यम से पास किया गया), और @StateObject बिना पैरामीटर के DetailViewModel बनाता है। onAppear में, पास किए गए ID के लिए डेटा लोड करने हेतु load(id:) विधि कॉल की जाती है। यह सुनिश्चित करता है कि ViewModel @StateObject तंत्र द्वारा बनाया गया है, लेकिन डेटा वर्तमान ID के साथ प्रत्येक व्यू प्रकट होने पर लोड होता है।
मुख्य गलती—चाइल्ड व्यू में @StateObject का उपयोग करना जो पैरेंट से ऑब्जेक्ट प्राप्त करते हैं। यदि ParentView @StateObject model बनाता है, और ChildView @StateObject var model: ModelType (डिफ़ॉल्ट पैरामीटर के साथ) घोषित करता है, तो ChildView अपना स्वतंत्र इंस्टेंस बनाएगा। पैरेंट और चाइल्ड ऑब्जेक्ट आपस में जुड़े नहीं होंगे, और एक में बदलाव दूसरे में प्रतिबिंबित नहीं होंगे।
दूसरी गलती—List या ForEach में @StateObject रखना। सूची का प्रत्येक तत्व अपना स्वयं का @StateObject बनाता है, जिससे कई स्वतंत्र इंस्टेंस बनते हैं। सूचियों के लिए, सही दृष्टिकोण @ObservedObject के माध्यम से सभी तत्वों को एक ObservableObject पास करना या List के अंदर @State के साथ Identifiable संरचनाओं का उपयोग करना है।
तीसरी समस्या—deinit सफाई का अभाव। @StateObject पूरे व्यू जीवनचक्र के लिए जीवित रहता है। यदि ऑब्जेक्ट टाइमर, Combine सब्सक्रिप्शन या नेटवर्क अनुरोध बनाता है, तो deinit को उन्हें रद्द करना चाहिए। अन्यथा, मेमोरी लीक और स्क्रीन बंद होने के बाद पृष्ठभूमि कार्य जारी रहना अपरिहार्य है। हमेशा Combine Cancellable स्टोर का उपयोग करें या deinit में टाइमर को अमान्य करें।
अक्सर पूछे जाने वाले प्रश्न
@StateObject को SwiftUI 2.0 में WWDC 2020 में iOS 14, macOS 11, watchOS 7 और tvOS 14 के साथ जोड़ा गया। इससे पहले, @ObservedObject ObservableObject के साथ काम करने का एकमात्र तरीका था, जिससे अक्सर डेटा हानि की समस्याएँ होती थीं।
नहीं, @StateObject Optional प्रकारों का समर्थन नहीं करता। ऑब्जेक्ट को घोषणा पर इनिशियलाइज़ किया जाना चाहिए। यदि आपको वैकल्पिक ऑब्जेक्ट की आवश्यकता है, तो वैकल्पिक प्रकार के साथ @ObservedObject या @EnvironmentObject का उपयोग करें।
ObservableObject के इनिशियलाइज़र और deinit में print(#function) जोड़ें। यदि रेंडर पर init कॉल नहीं होता—@StateObject सही ढंग से काम कर रहा है। यदि init हर बार कॉल होता है—@ObservedObject को @StateObject से बदलें।
हाँ, @StateObject UIHostingController के माध्यम से UIKit में एम्बेडेड SwiftUI व्यू में काम करता है। ऑब्जेक्ट का जीवनचक्र SwiftUI व्यू से बंधा है, UIViewController से नहीं। यदि SwiftUI व्यू बदला जाता है, @StateObject नष्ट हो जाता है।
अलग-अलग जिम्मेदारियों वाले कई छोटे @StateObjects। यह परीक्षण क्षमता, पुन: उपयोग और प्रदर्शन में सुधार करता है—जब एक ऑब्जेक्ट बदलता है, तो इंटरफ़ेस के केवल सब्सक्राइब किए गए भाग पुनः चित्रित होते हैं, पूरा व्यू नहीं।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें