@ObservedObject یک Property Wrapper در SwiftUI برای مشاهده یک نمونه ObservableObject است که از خارج منتقل شده است. برخلاف @StateObject، @ObservedObject شیء را ایجاد نمیکند — آن در تغییرات شیء موجود مشترک میشود. به گفته Apple Developer Documentation (2025)، @ObservedObject در viewهای فرزندی استفاده میشود که نیاز به ردیابی دادههای متعلق به والد دارند. @ObservedObject ارتباط واکنشی را بدون مدیریت چرخه عمر شیء فراهم میکند.
نکات اصلی
@ObservedObject یک Property Wrapper است که view را در تغییرات ObservableObject مشترک میکند. ObservableObject پروتکلی از فریمورک Combine است که نیاز به پیادهسازی publisher objectWillChange دارد. زمانی که هر ویژگی مشخص شده با @Published در داخل ObservableObject تغییر کند، publisher سیگنال ارسال میکند و SwiftUI تمام viewهای مشترک شده از طریق @ObservedObject را دوباره ترسیم میکند.
ویژگی اصلی @ObservedObject عدم مالکیت است. View مسئول ایجاد یا نابودی شیء نیست. شیء در view والد (از طریق @StateObject) ایجاد میشود یا از طریق @EnvironmentObject تزریق میشود. View فرزند فقط تغییرات را مشاهده میکند و بهروزرسانیها را دریافت میکند. اگر شیء در والد جایگزین شود، @ObservedObject به نمونه جدید سوئیچ میکند.
@ObservedObject برای سناریوهای اشتراک داده مناسب است: مدل کاربر، تنظیمات مشترک، وضعیت اتصال به سرور. وقتی چندین view در سطوح مختلف سلسلهمراتب باید دادههای یکسانی را نمایش دهند، @ObservedObject در هر view اشتراکهای مستقل اما هماهنگ به یک منبع ایجاد میکند.
تفاوت بین @ObservedObject و @StateObject یکی از رایجترین موضوعات سوالات در مصاحبههای SwiftUI است. قانون اصلی: @StateObject شیء را ایجاد و مالک میشود، @ObservedObject شیء موجود را مشاهده میکند. نقض این قانون منجر به از دست رفتن غیرمنتظره داده یا مقداردهی اولیه مضاعف میشود.
| ویژگی | @StateObject | @ObservedObject |
|---|---|---|
| ایجاد شیء | بله، هنگام مقداردهی view | خیر، آماده دریافت میکند |
| مالکیت | view فعلی | کامپوننت والد |
| نمونه واحد | بله، در کل چرخه عمر | خیر، ممکن است جایگزین شود |
| ایجاد مجدد هنگام رندر | خیر، حفظ میشود | بستگی به والد دارد |
| کجا استفاده شود | view ریشه مالک | viewهای فرزند |
@StateObject تضمین میکند که شیء یک بار ایجاد میشود و از مقداردهیهای مجدد ساختار view جان سالم به در میبرد. @ObservedObject شیء را از خارج دریافت میکند و در هر مقداردهی ساختار والد دوباره ایجاد میشود. اگر والد از @StateObject برای شیء استفاده کند، viewهای فرزند میتوانند با خیال راحت از @ObservedObject استفاده کنند — شیء در کل سلسلهمراتب یکتا خواهد بود.
مکانیزم ردیابی @ObservedObject بر اساس Combine و پروتکل ObservableObject است. هنگام مقداردهی، SwiftUI publisher objectWillChange را فراخوانی میکند — شیء باید قبل از تغییر ویژگی @Published سیگنال ارسال کند. Combine سیگنال را به گراف وابستگی SwiftUI منتقل میکند که تمام viewهای وابسته را به عنوان نیازمند بهروزرسانی علامتگذاری میکند. این به صورت همزمان قبل از تغییر مقدار رخ میدهد.
class WeatherService: ObservableObject {
@Published var temperature: Double = 22.0
@Published var city: String = "Moscow"
}
struct WeatherView: View {
@ObservedObject var weather: WeatherService
var body: some View {
VStack {
Text("\\(weather.city)")
Text("\\(weather.temperature)°C")
}
}
}
در لیستینگ WeatherService یک ObservableObject با دو ویژگی @Published است. WeatherView با اعلام @ObservedObject var weather: WeatherService نمونه را از والد دریافت میکند. وقتی temperature تغییر میکند، objectWillChange قبل از تنظیم مقدار جدید فعال میشود، SwiftUI WeatherView را دوباره ترسیم میکند و دمای فعلی نمایش داده میشود. اشتراک به طور خودکار توسط SwiftUI مدیریت میشود — توسعهدهنده نیازی به فراخوانی sink یا dispose ندارد.
الگوی اول — انتقال مدل از طریق مقداردهی اولیه. والد ObservableObject را از طریق @StateObject ایجاد میکند و آن را به viewهای فرزند به عنوان @ObservedObject منتقل میکند. این یک انتقال سلسلهمراتبی استاندارد داده است که در آن view ریشه چرخه عمر مدل را مدیریت میکند و تمام کامپوننتهای تو در تو در تغییرات مشترک میشوند.
الگوی دوم — EnvironmentObject، نسخه سراسری @ObservedObject از طریق SwiftUI Environment. شیء در سطح صحنه یا view ریشه تزریق میشود و به طور خودکار برای تمام کامپوننتهای فرزند بدون انتقال صریح از طریق مقداردهیکنندهها قابل دسترس است. در داخل view فرزند، @EnvironmentObject مشابه @ObservedObject کار میکند اما شیء را از محیط دریافت میکند.
الگوی سوم — ترکیب چند ObservableObject. در برنامههای پیچیده، view میتواند چندین شیء را مشاهده کند: @ObservedObject var user: UserService، @ObservedObject var network: NetworkMonitor. این کار مسئولیت را بین سرویسها تقسیم میکند و قابلیت تست هر کامپوننت را حفظ میکند.
struct DashboardView: View {
@ObservedObject var user: UserViewModel
@ObservedObject var network: NetworkMonitor
var body: some View {
VStack {
Text("خوش آمدید، \\(user.name)")
HStack {
Circle()
.fill(network.isConnected ? Color.green : Color.red)
.frame(width: 10, height: 10)
}
}
}
}
DashboardView UserViewModel و NetworkMonitor را مشاهده میکند. هر شیء مسئول حوزه داده خود است و به طور مستقل view را از تغییرات مطلع میکند. اگر شبکه قطع شود، NetworkMonitor isConnected را تغییر میدهد و SwiftUI DashboardView را دوباره ترسیم میکند و رنگ نشانگر را بهروز میکند. ترکیب ObservableObject روش ترجیحی سازماندهی داده در برنامههای SwiftUI است.
@Published یک Property Wrapper از Combine است که به طور خودکار به ویژگی داخل ObservableObject ناشر اضافه میکند. وقتی ویژگی @Published تغییر میکند، Combine از طریق publisher objectWillChange رویداد تولید میکند. SwiftUI هنگام استفاده از @ObservedObject یا @StateObject در این ناشر مشترک میشود و view را در هر مقدار جدید دوباره ترسیم میکند.
@Published از همه انواع از جمله اختیاری، مجموعهها و ساختارهای سفارشی پشتیبانی میکند. با این حال، برای مجموعهها (آرایهها، دیکشنریها) SwiftUI فقط جایگزینی مرجع را ردیابی میکند، نه تغییر محتوا را. برای تشخیص افزودن یا حذف عنصر، باید مجموعه را به طور کامل دوباره اختصاص دهید یا از ObservableObject با objectWillChange.send() دستی استفاده کنید.
نکته مهم: @Published فقط باید داخل کلاسی قرار گیرد که ObservableObject را پیادهسازی میکند. استفاده از @Published خارج از ObservableObject باعث خطای کامپایل میشود. همچنین @Published را نمیتوان برای ویژگیهای مقداردهی تنبل (lazy var) یا ویژگیهای محاسبهشده (computed property) اعمال کرد.
مهمترین خطا — استفاده از @ObservedObject برای ایجاد شیء. اگر در view والد @ObservedObject var model = UserViewModel() بنویسید، در هر رندر یک نمونه جدید UserViewModel ایجاد میشود. دادهها از دست میروند و اشتراکهای @Published دوباره ایجاد میشوند. همیشه از @StateObject برای ایجاد و از @ObservedObject فقط برای دریافت شیء آماده استفاده کنید.
خطای دوم — تغییر ویژگیهای @Published خارج از نخ اصلی. ObservableObject از Combine استفاده میکند که نیاز به ارسال تغییرات در نخ اصلی (main actor) دارد. اگر @Published را در صف پسزمینه تغییر دهید، SwiftUI ممکن است view را در زمان نامناسبی دوباره ترسیم کند و باعث race conditions شود. برای بهروزرسانی از DispatchQueue.main.async یا @MainActor استفاده کنید.
مشکل سوم — بهروزرسانیهای چرخهای. اگر تغییر @Published عوارض جانبی ایجاد کند که دوباره @Published را تغییر دهد، یک حلقه بینهایت ترسیم مجدد ایجاد میشود. راهحل: از پرچمهای محافظ (isUpdating) استفاده کنید یا منطق را به ObservableObjectهای مختلف با مرزهای مسئولیت مشخص تقسیم کنید.
سوالات متداول
بله، SwiftUI از @ObservedObject var model: UserViewModel? پشتیبانی میکند. با این حال، view تا زمانی که شیء nil باشد در تغییرات مشترک نخواهد شد. هنگام تخصیص مقدار، اشتراک به طور خودکار فعال میشود.
@ObservedObject شیء را از طریق مقداردهیکننده دریافت میکند، @EnvironmentObject از طریق SwiftUI Environment. @EnvironmentObject نیاز به انتقال صریح از طریق سازندهها ندارد، اما شیء باید در سطح بالایی سلسلهمراتب تزریق شود.
قبل از تغییر ویژگی objectWillChange.send() را فراخوانی کنید. این زمانی مفید است که @Published مناسب نیست (مثلاً برای ویژگیهای محاسبهشده یا عملیات مجموعهها که باید قبل از تغییر گزارش شود).
@ObservedObject و @Published جایگزینی مرجع را ردیابی میکنند، نه تغییر محتوای مجموعه را. برای ترسیم مجدد باید آرایه را دوباره اختصاص دهید: items.append(newItem) → items = items یا قبل از تغییر از objectWillChange.send() استفاده کنید.
خیر، @ObservedObject یک Property Wrapper SwiftUI است که فقط در داخل انواع پیادهکننده پروتکل View قابل دسترس است. برای ساختارهای معمولی مستقیماً از Combine با ObservableObjectPublisher استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید