@ObservedObject: چیست، مشاهده اشیاء و به‌روزرسانی View

نویسنده: IT Sectr منتشر شده: 2026-06-26 زمان مطالعه: 9 دقیقه

@ObservedObject — یک property wrapper در SwiftUI است که به View اجازه می‌دهد تغییرات ObservableObject ایجاد شده در جای دیگری از سلسله‌مراتب را مشاهده کند. بر خلاف @StateObject، @ObservedObject شیء ایجاد نمی‌کند — فقط در publisher objectWillChange آن مشترک می‌شود و هنگام به‌روزرسانی ویژگی‌های @Published، View را دوباره ترسیم می‌کند. این @ObservedObject را انتخاب درستی برای Viewهای فرزندی می‌کند که داده‌ها را از والد از طریق مقداردهنده اولیه دریافت می‌کنند. به گفته مقاله Paul Hudson — Hacking with Swift (2025)، معماری معمول یک برنامه SwiftUI به این صورت ساخته می‌شود: View ریشه از @StateObject برای ایجاد view model استفاده می‌کند و همه Viewهای فرزند آن را از طریق @ObservedObject دریافت می‌کنند که یک منبع حقیقت واحد بدون تکراری داده‌ها را تضمین می‌کند.

نکات اصلی

  • @ObservedObject — property wrapper برای مشاهده ObservableObject ایجاد شده در View والد.
  • مالک شیء نیست — بر خلاف @StateObject، @ObservedObject چرخه حیات شیء را مدیریت نمی‌کند.
  • اشتراک در تغییرات — با تغییر ویژگی‌های @Published، View به طور خودکار دوباره ترسیم می‌شود.
  • انتقال از طریق مقداردهنده اولیه — شیء از طریق پارامتر مقداردهنده اولیه به View فرزند منتقل می‌شود.
  • iOS 13+ — @ObservedObject از اولین نسخه SwiftUI در دسترس است، بر خلاف @StateObject (iOS 14+).

@ObservedObject در SwiftUI چیست

@ObservedObject — یک property wrapper است که View را در تغییرات ObservableObject مشترک می‌کند. وقتی شیء مشخص شده با @ObservedObject هر یک از ویژگی‌های خود که با @Published اعلام شده‌اند را تغییر می‌دهد، SwiftUI به طور خودکار View را دوباره ترسیم می‌کند. @ObservedObject شیء ایجاد نمی‌کند — فقط بین یک نمونه موجود ObservableObject و View که باید به تغییرات آن واکنش نشان دهد، ارتباط برقرار می‌کند.

تفاوت کلیدی بین @ObservedObject و @StateObject — مالکیت است. @ObservedObject فرض می‌کند که شیء در جایی بالاتر در سلسله‌مراتب View ایجاد و ذخیره شده است. View فرزند یک ارجاع به این شیء را از طریق مقداردهنده اولیه دریافت می‌کند و صرفاً آن را مشاهده می‌کند. اگر View فرزند دوباره ایجاد شود، همان ارجاع را از والد دریافت می‌کند — داده‌ها از دست نخواهند رفت.

به گفته Apple Developer Documentation — SwiftUI (2025)، @ObservedObject از iOS 13 در دسترس است، که آن را تنها گزینه برای مشاهده ObservableObject در پروژه‌هایی می‌کند که از نسخه‌های قدیمی iOS پشتیبانی می‌کنند. در iOS 14+ برای ایجاد اشیاء @StateObject ترجیح داده می‌شود، اما @ObservedObject برای انتقال اشیاء موجود همچنان مرتبط است.

@ObservedObject چگونه کار می‌کند

مکانیزم @ObservedObject بر اساس پروتکل ObservableObject از framework Combine است. هر کلاسی که با ObservableObject مطابقت دارد، به طور خودکار یک publisher objectWillChange دریافت می‌کند که قبل از تغییر هر ویژگی @Published سیگنال ارسال می‌کند. SwiftUI از طریق @ObservedObject در این publisher مشترک می‌شود و پس از دریافت سیگنال، View را به عنوان نیازمند ترسیم مجدد علامت‌گذاری می‌کند.

swift
class TaskViewModel: ObservableObject {
    @Published var tasks: [Task] = []
    @Published var isLoading = false
    
    func loadTasks() async {
        isLoading = true
        // واکشی داده‌ها
        isLoading = false
    }
}

struct TaskListView: View {
    @ObservedObject var viewModel: TaskViewModel
    
    var body: some View {
        List(viewModel.tasks) { task in
            Text(task.title)
        }
        .task { await viewModel.loadTasks() }
    }
}

وقتی View والد viewModel را از طریق مقداردهنده اولیه به TaskListView منتقل می‌کند، SwiftUI بین شیء و View ارتباط برقرار می‌کند. با تغییر آرایه tasks یا پرچم isLoading، SwiftUI TaskListView را دوباره ترسیم می‌کند. شیء در این میان بدون تغییر می‌ماند — در View والد از طریق @StateObject ذخیره می‌شود.

@ObservedObject در مقابل @StateObject: چه زمانی از کدام استفاده کنیم

تفاوت بین @ObservedObject و @StateObject — تفاوت بین ناظر و مالک است. @StateObject شیء ایجاد می‌کند و چرخه حیات آن را مدیریت می‌کند. @ObservedObject فقط شیئی را مشاهده می‌کند که در جای دیگری ایجاد و ذخیره شده است. انتخاب بین آنها با مسئولیت View نسبت به داده‌ها تعیین می‌شود.

سناریوتوصیهدلیل
View داده ایجاد می‌کند@StateObjectView مالک شیء است و مسئول چرخه حیات آن است
View داده دریافت می‌کند@ObservedObjectView فقط مشاهده می‌کند، شیء در والد زندگی می‌کند
پشتیبانی iOS 13@ObservedObject@StateObject در دسترس نیست، از @ObservedObject با مدیریت دستی استفاده کنید
کامپوننت قابل استفاده مجدد@ObservedObjectکامپوننت نباید داده ایجاد کند — آن را از خارج دریافت می‌کند

قانون اصلی: اگر View شیء ایجاد می‌کند — @StateObject. اگر View شیء دریافت می‌کند — @ObservedObject. نقض این قانون به سمت @ObservedObject برای ایجاد شیء منجر به از دست رفتن داده در بازسازی View می‌شود. نقض به سمت @StateObject برای دریافت شیء یک نمونه تکراری مستقل از والد ایجاد می‌کند.

نمونه‌های استفاده از @ObservedObject

سناریوی معمول استفاده از @ObservedObject — یک لیست وظایف، که در آن View ریشه یک view model ایجاد می‌کند و سلول لیست آن را از طریق @ObservedObject دریافت می‌کند. هر سلول می‌تواند متدهای view model را فراخوانی کند و تغییرات به طور خودکار در کل لیست نمایش داده می‌شوند، زیرا همه سلول‌ها یک شیء را مشاهده می‌کنند.

swift
struct TaskRow: View {
    @ObservedObject var viewModel: TaskViewModel
    let task: Task
    
    var body: some View {
        HStack {
            Text(task.title)
            Spacer()
            Button("انجام شد") {
                viewModel.completeTask(task)
            }
        }
    }
}

struct TaskListContainer: View {
    @StateObject var viewModel = TaskViewModel()
    
    var body: some View {
        List(viewModel.tasks) { task in
            TaskRow(viewModel: viewModel, task: task)
        }
    }
}

در این مثال TaskListContainer viewModel را از طریق @StateObject ایجاد می‌کند و هر TaskRow آن را از طریق @ObservedObject دریافت می‌کند. وقتی کاربر “Done” را در هر سطری کلیک می‌کند، viewModel.completeTask ویژگی published را تغییر می‌دهد و همه View‌هایی که این شیء را مشاهده می‌کنند به طور خودکار به‌روز می‌شوند.

خطاهای معمول با @ObservedObject

رایج‌ترین خطا — استفاده از @ObservedObject برای ایجاد شیء در داخل View است. وقتی View بازسازی می‌شود (مثلاً با تغییر state)، SwiftUI یک نمونه جدید ObservableObject ایجاد می‌کند که منجر به از دست رفتن تمام داده‌های جمع‌آوری شده می‌شود. این خطا به خصوص در NavigationStack دردناک است، جایی که کاربر می‌تواند فرمی را پر کند و هنگام بازگشت داده‌ها را از دست بدهد.

خطا: @ObservedObject به جای @StateObject

swift
// ❌ از دست رفتن داده: @ObservedObject شیء را نگه نمی‌دارد
struct FormView: View {
    @ObservedObject var formVM = FormViewModel()
    // فرم VM جدید در هر بازسازی View ایجاد می‌شود!
}

// ✅ درست: @StateObject شیء را نگه می‌دارد
struct FormView: View {
    @StateObject var formVM = FormViewModel()
    // شیء یک بار در طول عمر View ایجاد شد
}

خطا: انتقال @StateObject جایی که @ObservedObject نیاز است

اگر View فرزند همان ObservableObject را از طریق @StateObject اعلام کند، یک کپی مستقل ایجاد می‌کند. تغییرات در شیء والد در فرزند دیده نخواهد شد و بالعکس. همیشه برای Viewهای فرزندی که شیء را از خارج دریافت می‌کنند از @ObservedObject استفاده کنید.

جایگزین‌های @ObservedObject در SwiftUI

در SwiftUI مدرن چندین جایگزین برای @ObservedObject وجود دارد، هر کدام با مزایای خود. انتخاب به معماری برنامه، نسخه iOS و سناریوی استفاده خاص بستگی دارد.

  • @EnvironmentObject — به شما امکان می‌دهد شیء را از محیط SwiftUI بدون انتقال صریح از طریق مقداردهنده اولیه دریافت کنید. برای اشیایی که در بسیاری از صفحه‌ها نیاز هستند مناسب است، اما نیاز به تزریق صریح از طریق .environmentObject() دارد.
  • @State + @Binding — برای انواع مقدار ساده به ObservableObject نیازی نیست. برای ذخیره از @State و برای انتقال به Viewهای فرزند از @Binding استفاده کنید.
  • @AppStorage — برای مقادیر UserDefaults که باید به طور خودکار با View همگام شوند.
  • @SceneStorage — برای ذخیره وضعیت موقت بین راه‌اندازی مجدد صحنه (مثلاً موقعیت در لیست).

انتخاب بین @ObservedObject و @EnvironmentObject — یک مسئله سبک و معماری است. @ObservedObject وابستگی‌های View را از طریق مقداردهنده اولیه به وضوح نشان می‌دهد که کد را قابل پیش‌بینی‌تر می‌کند. @EnvironmentObject برای سلسله‌مراتب عمیق مناسب است، اما وابستگی‌ها را پنهان می‌کند که می‌تواند اشکال‌زدایی را دشوار کند.

سوالات متداول

آیا می‌توان از @ObservedObject بدون @StateObject در والد استفاده کرد؟

بله، اگر شیء در خارج از SwiftUI ایجاد و ذخیره شده باشد — مثلاً در AppDelegate یا singleton. در این حالت @ObservedObject صرفاً در تغییرات شیء موجود مشترک می‌شود. با این حال برای اشیاء ایجاد شده در داخل سلسله‌مراتب SwiftUI همیشه به @StateObject در جایی بالاتر نیاز است.

چرا @ObservedObject گاهی View را به‌روز نمی‌کند؟

محتمل‌ترین دلیل — ویژگی از طریق @Published تغییر نمی‌کند یا خود شیء تغییر نمی‌کند، بلکه ساختار داخلی آن بدون فراخوانی objectWillChange تغییر می‌کند. برای مجموعه‌ها از تخصیص یک کپی جدید استفاده کنید: array.append() کافی نیست — باید خود آرایه را دوباره از طریق array = array + [element] تخصیص دهید.

آیا @ObservedObject بر عملکرد تأثیر می‌گذارد؟

@ObservedObject به خودی خود بار قابل توجهی ایجاد نمی‌کند. مشکلات زمانی ایجاد می‌شوند که تغییرات مکرر ویژگی‌های @Published رخ دهد — هر تغییر باعث ترسیم مجدد همه Viewهای ناظر می‌شود. برای بهینه‌سازی از EquatableView استفاده کنید، تعداد ویژگی‌های published را کاهش دهید و از به‌روزرسانی‌های غیرضروری خودداری کنید.

@ObservedObject چه تفاوتی با @Binding دارد؟

@ObservedObject کل یک کلاس ObservableObject را مشاهده می‌کند و View را با هر تغییری در ویژگی‌های published آن دوباره ترسیم می‌کند. @Binding یک ارتباط دوطرفه با یک مقدار خاص (String، Int، Bool) ایجاد می‌کند و اجازه خواندن و نوشتن آن را می‌دهد. @Binding سبک‌تر است و به ObservableObject نیاز ندارد.

آیا می‌توان @ObservedObject را با @Published در یک کلاس ترکیب کرد؟

بله، این یک الگوی استاندارد است. @Published در داخل ObservableObject به طور خودکار با @ObservedObject یکپارچه می‌شود. هر ویژگی @Published یک ناظر به publisher objectWillChange اضافه می‌کند. با تغییر هر یک از آنها، همه Viewهای دارای @ObservedObject برای این شیء دوباره ترسیم می‌شوند.

خلاصه

  • @ObservedObject — property wrapper برای مشاهده ObservableObject ایجاد شده در جای دیگر سلسله‌مراتب.
  • مالک شیء نیست — بر خلاف @StateObject، @ObservedObject چرخه حیات را مدیریت نمی‌کند و شیء ایجاد نمی‌کند.
  • اشتراک از طریق Combine — SwiftUI به طور خودکار در publisher objectWillChange ObservableObject مشترک می‌شود.
  • iOS 13+ — @ObservedObject از اولین نسخه SwiftUI در دسترس است که برای پروژه‌های با پشتیبانی قدیمی مهم است.
  • انتقال از طریق مقداردهنده اولیه — شیء به وضوح به View فرزند منتقل می‌شود که وابستگی‌ها را شفاف می‌کند.
  • خطای مالکیت — استفاده از @ObservedObject برای ایجاد شیء منجر به از دست رفتن داده در بازسازی View می‌شود.
  • جایگزین‌ها — @EnvironmentObject برای تزریق از طریق محیط، @State/@Binding برای انواع مقدار.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید