@StateObject SwiftUI میں ایک Property Wrapper ہے جو براہِ راست view میں ObservableObject ایک ایک مثال بنانے اور اس کی مالکیت رکھنے کے لیے ہے۔ SwiftUI ضمانت دیتا ہے کہ آبجیکٹ view کے لائف سائکل میں ایک بار ابتدائیہ ہوتا ہے اور دوبارہ رینڈر پر دوبارہ نہیں بنایا جاتا۔ Apple Developer Documentation (2025) کے مطابق، @StateObject جڒ ویو کے لیے تجویز کیا جاتا ہے جو ڈیٹا کا ذریعہ بناتے ہیں۔ @StateObject SwiftUI کے درجہ بندی میں ObservableObject کی مالکیت کے لیے صحیح چوناو ہے۔
اہم نکات
@StateObject ایک Property Wrapper ہے جو SwiftUI 2.0 (iOS 14) میں متعارف کیا گیا، جو @ObservedObject اور @State کی صلاحیتوں کو اکٹھا کرتا ہے۔ @ObservedObject کی طرح، یہ ObservableObject میں تبدیلیوں کی سبسکرائیب کرتا ہے۔ @State کی طرح، یہ ضمانت دیتا ہے کہ ڈیٹا view کے ضابطہ کے بار بار ابتدائیہ سے بچ جاتا ہے۔ @StateObject آبجیکٹ ایک بار تب بناتا ہے جب view پہلی بار سکرین پر آتا ہے اور اسے SwiftUI کے ہیپ میں ذخیرہ کرتا ہے۔
@StateObject سے پہلے، ڈیولپرز تمام ObservableObjects کے لیے @ObservedObject استعمال کرتے تھے، جن میں view میں بنائے گئے آبجیکٹ بھی شامل ہیں۔ اس سے اکثر ڈیٹا کا نقصان ہوتا تھا جب پیرنٹ view اپڈیٹ ہوتا تھا، جس سے view کا ضابطہ دوبارہ بنتا تھا اور @ObservedObject کی مثال اپنے ساتھ لے جاتا تھا۔ @StateObject نے استحکام کی ضمانت شامل کرکے اس مسئلے کو حل کیا۔
بنیادی قاعدہ: @StateObject اس view میں استعمال ہوتا ہے جو پہلے سے طے کے ابتدائیہ (let model = ViewModel()) میں آبجیکٹ بناتا ہے۔ چائلڈ view جو یہ آبجیکٹ وصول کرتے ہیں @ObservedObject استعمال کرتے ہیں۔ یہ علاحدگی پورے درجہ بندی میں سچ کا ایک ذریعہ یقینی بناتی ہے۔
SwiftUI @State کے مشابہ اسٹوریج مینجر کے ذریعہ @StateObject کے لائف سائکل کا انتظام کرتا ہے۔ جب view پہلی بار ظاہر ہوتا ہے، SwiftUI آبجیکٹ کے لیے میمری مختص کرتا ہے اور اسے ایک مستقل علاقے میں ذخیرہ کرتا ہے۔ بعد کے رینڈر (body کول) پر، آبجیکٹ دوبارہ نہیں بنتا—موجودہ مثال استعمال ہوتی ہے۔ آبجیکٹ تب تک زندہ رہتا ہے جب تک view درجہ بندی میں ہے۔
جب view کو درجہ بندی سے ہٹایا جاتا ہے، SwiftUI @StateObject کو ختم کر دیتا ہے، deinit کو کول کرتا ہے۔ جب view واپس درجہ بندی میں شامل کیا جاتا ہے، ایک نئی مثال بنائی جاتی ہے۔ ڈزائن کرتے وقت اس پر غور کرنا اہم ہے: اگر آپ کو view ہٹانے کے درمیان ڈیٹا محفوظ رکھنے کی ضرورت ہے، تو استقلال کے لیے ایک سروس پرت (singleton یا 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 کے درمیان انتخاب اس بات پر منحصر ہے کہ آبجیکٹ کا مالک کون ہے۔ اگر view آبجیکٹ بناتا ہے—@StateObject۔ اگر view تیار آبجیکٹ وصول کرتا ہے—@ObservedObject۔ یہ قاعدہ اتنا اہم ہے کہ Xcode ایک انتباہ کرتا ہے جب @StateObject ایک چائلڈ view میں استعمال کیا جاتا ہے جو ایک ابتدائیہ کے ذریعہ آبجیکٹ وصول کرتا ہے۔
| صورتحال | تجویز شدہ Wrapper |
|---|---|
| View ViewModel() کے ذریعہ ماڈل بناتا ہے | @StateObject |
| View ماڈل والد سے وصول کرتا ہے | @ObservedObject |
| ماڈل ایک view میں استعمال ہوتا ہے | @StateObject |
| ماڈل Environment کے ذریعہ پہنچایا جاتا ہے | @EnvironmentObject |
| پیش نمائش کے لیے ماڈل ضروری ہے | @ObservedObject + mock |
عمل میں، پروجیکٹ کے شروع میں، @StateObject اکثر جڒ view میں اور @ObservedObject تمام چائلڈ view میں استعمال ہوتا ہے۔ جیسے جیسے ایپلیکیشن بڑھتا ہے، درجہ بندی کو سادہ کرنے کے لیے کچھ @StateObject انسٹنسز کو @EnvironmentObject سے بدلا جا سکتا ہے۔ تاہم، @StateObject اپنے منطق کے ساتھ ماڈیولر سکرین کے لیے بہترین چوناو رہتا ہے۔
پہلا پٹرن—@StateObject کے ساتھ MVVM۔ ObservableObject کے طور پر ViewModel @StateObject کے ذریعہ view میں بنایا جاتا ہے۔ ViewModel میں @Published خوصیات اور کاروباری منطق ہوتا ہے۔ View تبدیلیوں کی سبسکرائیب کرتا ہے اور انٹرفیس کو اپڈیٹ کرتا ہے۔ یہ نظریہ تجربہ قابل علاحدگی فراھم کرتا ہے: ViewModel کو سیڈھے ایک مثال بنا کر UI کے بغیر ٹیسٹ کیا جا سکتا ہے۔
دوسرا پٹرن—انحصارات کے ساتھ @StateObject۔ اگر ViewModel کو خدمات کی ضرورت ہے، تو پیرامیٹر کے ساتھ ابتدائیہ استعمال کریں۔ مثال کے طور پر، @StateObject var viewModel = UserViewModel(api: APIClient.shared)۔ تاہم پرِ احتیاط کریں: پیرامیٹر ہر body رینڈر پر حساب کیے جاتے ہیں، لیکن آبجیکٹ صرف ایک بار بنتا ہے۔ SwiftUI @StateObject کے بعد کے ابتدائیوں کو نظرانداز کرتا ہے۔
تیسرا پٹرن—نیژٹڈ @StateObject۔ SwiftUI میں، آپ ایک view میں متعدد @StateObject رکھ سکتے ہیں، لیکن یہ شاید ھی جائز ہے۔ عام طور پر ایک @StateObject view کے پورے ڈیٹا سیٹ کو سنبھالتا ہے۔ اگر منطق بہت زیادہ پیچیدہ ہو جائے، تو اسے ایک @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 میں انجکٹ کیے جاتے ہیں۔ کوئی بھی چائلڈ view ابتدائیہ زنجیر سے گزرے بغیر @EnvironmentObject کے ذریعہ ان تک رسائی حاصل کر سکتا ہے۔
@StateObject کسی بھی پیرامیٹر کے ساتھ ابتدائیہ کی حمایت کرتا ہے، لیکن ایک اہم شرط کے ساتھ: ابتدائیہ صرف ایک بار کول ہوتا ہے۔ بعد کے body رینڈر پر، پیرامیٹر میں نئی قیمتیں نظرانداز کر دی جاتی ہیں۔ اس کا مطلب ہے کہ اگر آپ @State var id: Int = 5 کو @StateObject var vm = ViewModel(id: id) میں پہنچاتے ہیں، تو جب id بدلتا ہے، ViewModel نئی قیمت وصول نہیں کرے گا۔
اس مسئلے کو حل کرنے کے لیے، مطابقت کے لیے onReceive یا onAppear استعمال کریں۔ Combine کے ذریعہ ViewModel کے اندر پیرامیٹر تبدیلیوں کی سبسکرائیب کریں یا view کی سطح پر .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 کے ساتھ ہر view ظاہر ہونے پر لوڈ ہوتا ہے۔
بڒ غلطی—ایسے چائلڈ view میں @StateObject استعمال کرنا جو والد سے آبجیکٹ وصول کرتے ہیں۔ اگر ParentView @StateObject model بناتا ہے اور ChildView @StateObject var model: ModelType (ڈفلٹ پیرامیٹر کے ساتھ) کا اعلان کرتا ہے، تو ChildView اپنی آزاد مثال بنائے گا۔ والد اور بچے کے آبجیکٹ آپس میں منصل نہیں ہوں گے، اور ایک میں تبدیلیاں دوسرے میں منعکس نہیں ہوں گیں۔
دوسری غلطی—List یا ForEach میں @StateObject رکھنا۔ فہرست کا ہر عنصر اپنا @StateObject بناتا ہے، جس سے متعدد آزاد مثالیں بنتی ہیں۔ فہرستوں کے لیے، صحیح نظریہ یہ ہے کہ @ObservedObject کے ذریعہ تمام عناصر کو ایک ObservableObject پہنچائیں یا List کے اندر @State کے ساتھ Identifiable ساختیں استعمال کریں۔
تیسرا مسئلہ—deinit صفائی کی کمی۔ @StateObject view کے پورے لائف سائکل کے لیے زندہ رہتا ہے۔ اگر آبجیکٹ ٹائیمرز، 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 view میں کام کرتا ہے۔ آبجیکٹ کا لائف سائکل UIViewController سے نہیں بلکہ SwiftUI view سے منصل ہے۔ اگر SwiftUI view بدل دیا جائے، تو @StateObject ختم کر دیا جاتا ہے۔
علاحدہ ذمہ داریوں کے ساتھ کئی چھوٹے @StateObjects۔ یہ ٹیسٹیبلٹی، دوبارہ استعمال اور کارکردگی میں بھتری کرتا ہے—جب ایک آبجیکٹ بدلتا ہے، تو انٹرفیس کے صرف سبسکرائیب شدہ حصی دوبارہ بنتے ہیں، پورا view نہیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں