@StateObject হল SwiftUI-এ একটি Property Wrapper যা সরাসরি view-এ ObservableObject ইনস্ট্যান্স তৈরি এবং মালিকানা রাখার জন্য। 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-এর আগে, ডেভেলপাররা সমস্ত ObservableObject-এর জন্য @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 অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন