@EnvironmentObject SwiftUI میں ایک property wrapper ہے جو درجہ بندی میں کسی بھی View کو ابتداء کاروں کی زنجیر کے ذریعے واضح طور پر منتقل کیے بغیر ObservableObject تک رسائی حاصل کرنے کی اجازت دیتا ہے۔ آبجیکٹ کو .environmentObject() موڈیفائر کا استعمال کرتے ہوئے درجہ بندی کے ایک مخصوص سطح پر ماحول میں انجیکٹ کیا جاتا ہے، جس کے بعد تمام چائلڈ View اسے @EnvironmentObject کے ذریعے حاصل کر سکتے ہیں۔ یہ آبجیکٹ کو استعمال نہ کرنے والے درمیانی View کے ذریعے آبجیکٹ منتقل کرنے کی ضرورت کو ختم کرتا ہے — نام نہاد prop drilling۔ John Sundell — Swift by Sundell (2025) کے ایک مضمون کے مطابق، @EnvironmentObject کراس اسکرین ڈیٹا کے لیے خاص طور پر مفید ہے: صارف سیشن، ایپ سیٹنگز، شاپنگ کارٹ مینیجر یا مقامی ڈیٹا کیش۔
اہم نکات
@EnvironmentObject ایک property wrapper ہے جو SwiftUI View کو ایپلیکیشن کے ماحول سے ObservableObject تک رسائی حاصل کرنے کی اجازت دیتا ہے۔ ماحول ایک کنٹینر ہے جس میں .environmentObject() موڈیفائر کا استعمال کرتے ہوئے View درجہ بندی کی کسی بھی سطح پر آبجیکٹ رکھے جا سکتے ہیں۔ ایک بار جب آبجیکٹ ماحول میں رکھ دیا جائے تو، کوئی بھی چائلڈ View صرف @EnvironmentObject کے ساتھ ایک پراپرٹی اعلان کرکے اور آبجیکٹ کی قسم بتا کر اس تک رسائی حاصل کر سکتا ہے۔
@EnvironmentObject کا بنیادی مقصد ہر درمیانی سطح کے ذریعے آبجیکٹ منتقل کیے بغیر گہری View درجہ بندی کے ذریعے ڈیٹا منتقل کرنے کے مسئلے کو حل کرنا ہے۔ NavigationStack، TabView اور موڈل ونڈوز کی شاخوں والی پیچیدہ ایپلیکیشنز میں، @EnvironmentObject بوائلرپلیٹ کوڈ کو ختم کرکے فن تعمیر کو نمایاں طور پر آسان بناتا ہے۔
Apple Developer Documentation — Environment (2025) کے مطابق، @EnvironmentObject PreferenceKey اور View شناخت پر مبنی اندرونی SwiftUI میکانزم استعمال کرتا ہے۔ ہر View اپنے ماحول کا ایک حوالہ محفوظ کرتا ہے، جو پیرنٹ View سے وراثت میں ملتا ہے اور .environmentObject() کا استعمال کرتے ہوئے بڑھایا جا سکتا ہے۔ آبجیکٹ کی تلاش روٹ View تک درجہ بندی میں اوپر جاتی ہے۔
class UserSession: ObservableObject {
@Published var isLoggedIn = false
@Published var userName: String = ""
func login(name: String) {
userName = name
isLoggedIn = true
}
}
@main
struct MyApp: App {
@StateObject var session = UserSession()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(session)
}
}
}
@EnvironmentObject SwiftUI میں بنائے گئے انحصار انجیکشن (DI) میکانزم کی بنیاد پر کام کرتا ہے۔ جب آپ ایک View پر .environmentObject() کال کرتے ہیں، SwiftUI آبجیکٹ کو اس View اور اس کی تمام اولاد سے منسلک ایک خاص اسٹوریج میں محفوظ کرتا ہے۔ جب ایک چائلڈ View اسی قسم کا @EnvironmentObject اعلان کرتا ہے، SwiftUI والدین کے درجہ بندی میں اوپر چڑھتے ہوئے ماحول میں آبجیکٹ تلاش کرتا ہے۔
ایک اہم خصوصیت — آبجیکٹ کی قسم ماحول میں تلاش کے لیے کلید کے طور پر استعمال ہوتی ہے۔ اگر ماحول میں ایک ہی قسم کی دو آبجیکٹ موجود ہوں، SwiftUI درجہ بندی میں موجودہ View کے قریب ترین آبجیکٹ تلاش کرتا ہے۔ جب آبجیکٹ WindowGroup سطح پر انجیکٹ کی جاتی ہے، تو یہ ایپلیکیشن کی تمام اسکرینوں کے لیے عالمی طور پر دستیاب ہو جاتی ہے، جو عام مقصد کی خدمات کے لیے آسان ہے۔
objc.io — SwiftUI Architecture (2025) کے مطابق، اندرونی طور پر @EnvironmentObject @ObservedObject جیسا ہی میکانزم استعمال کرتا ہے، لیکن درجہ بندی میں آبجیکٹ تلاش کرنے کے لیے ایک اضافی تجریدی پرت کے ساتھ۔ SwiftUI آبجیکٹ کو کاپی نہیں کرتا اور نہ ہی نیا بناتا ہے — یہ موجودہ مثال کا حوالہ منتقل کرتا ہے، لہذا آبجیکٹ میں تبدیلیاں @EnvironmentObject استعمال کرنے والے تمام View کو خود بخود نظر آتی ہیں۔
@EnvironmentObject اور @ObservedObject دونوں ایک ہی بنیادی کام انجام دیتے ہیں — وہ ObservableObject میں تبدیلیوں کے لیے View کو سبسکرائب کرتے ہیں۔ فرق آبجیکٹ منتقل کرنے کے میکانزم میں ہے۔ @ObservedObject کو ابتداء کار کے ذریعے واضح منتقلی کی ضرورت ہوتی ہے، جبکہ @EnvironmentObject ہر درمیانی View میں واضح طور پر بتائے بغیر ماحول سے آبجیکٹ حاصل کرتا ہے۔
| خصوصیت | @EnvironmentObject | @ObservedObject |
|---|---|---|
| منتقلی | درجہ بندی کی سطح پر .environmentObject() کے ذریعے | ہر View کے ابتداء کار کے ذریعے |
| انحصار کی مرئیت | پوشیدہ — View کے دستخط میں نظر نہیں آتی | واضح — View کے init میں نظر آتی ہے |
| درمیانی View | آبجیکٹ کے بارے میں نہیں جانتے | آبجیکٹ کو آگے منتقل کرنا ہوگا |
| غلطی کا خطرہ | آبجیکٹ غائب ہونے پر Runtime crash | مرتبہ وقت کی جانچ (اگر پیرامیٹر لازمی ہو) |
| Prop drilling | ختم کرتا ہے | دستی منتقلی کی ضرورت ہے |
@EnvironmentObject اور @ObservedObject کے درمیان انتخاب فن تعمیر پر منحصر ہے۔ اگر آبجیکٹ درجہ بندی میں گہرائی میں اور کئی اسکرینوں پر درکار ہو — @EnvironmentObject زیادہ آسان ہے۔ اگر فن تعمیر کو جانچ اور پڑھنے کی اہلیت کے لیے انحصار کی واضح وضاحت درکار ہو — @ObservedObject ترجیح دیتا ہے۔
سب سے عام منظرنامہ ایک صارف سیشن ہے جسے ایپلیکیشن کی تمام اسکرینوں پر قابل رسائی ہونا چاہیے۔ ایپلیکیشن کی جڑ میں .environmentObject() کے ذریعے UserSession انجیکٹ کرکے، کوئی بھی اسکرین صارف کے ڈیٹا اور اجازت کی حالت تک رسائی حاصل کر سکتی ہے۔
struct ProfileView: View {
@EnvironmentObject var session: UserSession
var body: some View {
VStack {
if session.isLoggedIn {
Text("Hello, \(session.userName)")
Button("Logout") {
session.isLoggedIn = false
}
} else {
LoginView()
}
}
}
}
struct SettingsView: View {
@EnvironmentObject var session: UserSession
var body: some View {
Form {
Text("Logged in as \(session.userName)")
}
}
}
غور کریں کہ نہ ProfileView اور نہ ہی SettingsView ابتداء کار کے ذریعے سیشن حاصل کرتے ہیں۔ وہ صرف @EnvironmentObject var session: UserSession کا اعلان کرتے ہیں، اور SwiftUI خود بخود ماحول میں آبجیکٹ تلاش کر لیتا ہے۔ یہ موجودہ ڈیٹا منتقلی کوڈ کو تبدیل کیے بغیر نئی اسکرینز شامل کرنے کی اجازت دیتا ہے۔
@EnvironmentObject کا بنیادی خطرہ runtime crash ہے اگر آبجیکٹ ماحول میں انجیکٹ نہ کی گئی ہو۔ اختیاری پیرامیٹرز کے برعکس، @EnvironmentObject nil نہیں ہو سکتا۔ اگر @EnvironmentObject والا View اسکرین پر ظاہر ہوتا ہے اور پیرنٹ View نے اس قسم کے لیے .environmentObject() کال نہیں کی ہے، تو ایپ فوری طور پر “Fatal error: No ObservableObject of type X found” کے ساتھ کریش ہو جاتی ہے۔
اگر آپ درجہ بندی کی مختلف سطحوں پر ایک ہی قسم کی دو آبجیکٹ انجیکٹ کرتے ہیں، تو چائلڈ View درجہ بندی کے مطابق قریب ترین وصول کرے گا۔ یہ الجھن کا سبب بن سکتا ہے اگر ڈویلپر توقع کرے کہ جڑ کے ماحول کی آبجیکٹ ایک موڈل ونڈو میں دستیاب ہوگی جس کا اپنا ماحول اسی قسم کی آبجیکٹ کے ساتھ ہے۔
SwiftUI کی ترقی کے ساتھ، انحصار کے انتظام کے متبادل طریقے سامنے آئے ہیں جو @EnvironmentObject کی کچھ کمیاں دور کرتے ہیں — بنیادی طور پر انحصار کی پوشیدگی اور runtime crash کا خطرہ۔
طریقہ کار کا انتخاب ٹیم کے سائز اور ایپلیکیشن کی پیچیدگی پر منحصر ہے۔ چھوٹے پروجیکٹس کے لیے، @EnvironmentObject بہت اچھا کام کرتا ہے۔ بڑے پروجیکٹس کے لیے جن میں درجنوں اسکرینز اور سخت جانچ کی ضروریات ہیں، @ObservedObject یا DI کنٹینر کے ذریعے واضح منتقلی ترجیح دی جاتی ہے۔
اکثر پوچھے گئے سوالات
جی ہاں، ایک View مختلف اقسام کے جتنے چاہے @EnvironmentObject کا اعلان کر سکتا ہے۔ SwiftUI ہر قسم کو ماحول میں آزادانہ طور پر تلاش کرتا ہے۔ یہ اس وقت مفید ہے جب View کو بیک وقت صارف سیشن، سیٹنگز اور شاپنگ کارٹ تک رسائی درکار ہو — ہر آبجیکٹ علیحدہ طور پر انجیکٹ کی جاتی ہے۔
View کو ظاہر کرنے کی کوشش کرتے ہوئے Preview runtime error کے ساتھ کریش ہو جائے گا۔ @EnvironmentObject استعمال کرنے والے View کے لیے Preview میں ہمیشہ .environmentObject() شامل کریں۔ ٹیسٹ ڈیٹا کے ساتھ فرضی آبجیکٹ استعمال کریں تاکہ Preview صحیح طریقے سے کام کرے اور حقیقت پسندانہ حالت دکھائے۔
نہیں، @EnvironmentObject صرف ObservableObject کے مطابق ایک ٹھوس کلاس کی قسم کے ساتھ کام کرتا ہے۔ پروٹوکول کے لیے آپ کو type erasure یا ریپر استعمال کرنا ہوگا: ایک ریپر کلاس بنائیں جو پروٹوکول قسم کی آبجیکٹ کا حوالہ رکھتی ہے، اور ریپر کو @EnvironmentObject کے ذریعے انجیکٹ کریں۔
ٹیسٹ ڈیٹا کے ساتھ ایک ObservableObject مثال بنائیں اور اسے ٹیسٹ میں .environmentObject(testObject) کے ذریعے View کو منتقل کریں۔ SwiftUI UI جانچ کے لیے یہ معیاری نمونہ ہے۔ یونٹ ٹیسٹ کے لیے، منطق کو ObservableObject میں الگ کریں اور View سے علیحدہ طور پر اس کی جانچ کریں۔
@EnvironmentObject کارکردگی پر کوئی اضافی بوجھ نہیں ڈالتا کیونکہ یہ صرف آبجیکٹ کا حوالہ منتقل کرتا ہے، کاپی نہیں۔ تاہم، عالمی آبجیکٹ میں @Published خصوصیات کی بار بار اپ ڈیٹ بہت سے View کو بیک وقت دوبارہ رینڈر کرنے کا سبب بن سکتی ہے، جو کارکردگی کو متاثر کر سکتی ہے۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں