@EnvironmentObject SwiftUI-তে একটি property wrapper যা হায়ারার্কির যেকোনো View-কে ইনিশিয়ালাইজারের চেইনের মাধ্যমে স্পষ্টভাবে পাস না করেই ObservableObject-এ অ্যাক্সেস করতে দেয়। অবজেক্টটি .environmentObject() মডিফায়ার ব্যবহার করে হায়ারার্কির একটি নির্দিষ্ট স্তরে পরিবেশে ইনজেক্ট করা হয়, যার পরে সমস্ত চাইল্ড View @EnvironmentObject-এর মাধ্যমে এটি অ্যাক্সেস করতে পারে। এটি মধ্যবর্তী View-গুলির মাধ্যমে অবজেক্ট পাস করার প্রয়োজনীয়তা দূর করে যারা এটি ব্যবহার করে না — তথাকথিত prop drilling। জন সানডেল — 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 | Compile-time চেক (যদি প্যারামিটার বাধ্যতামূলক হয়) |
| 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 অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন