0Pricing
Swift Academy · درس

ربط نماذج العرض بالعروض

اربط نماذج العرض باستخدام SwiftUI و Combine.

ربط نماذج العرض بالعروض درس مجاني في Swift Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Swift Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Swift Academy 4 دروس في المجموع.

ربط ViewModel بـ View

لا تكون ViewModel مفيدة إلا عندما تتفاعل View مع تغيّراتها. في SwiftUI، تعتمد هذه الاستجابة على مغلفات الخصائص المستندة إلى Combine، وهي @Published و@StateObject و@ObservedObject.

تشكّل هذه العناصر معًا ارتباطًا تلقائيًا: فعندما تتغيّر ViewModel، تعيد View العرض.

ObservableObject

لكي تراقبها SwiftUI، يجب أن تتوافق ViewModel مع ObservableObject. يزوّدها هذا البروتوكول بناشر objectWillChange يُطلَق قبل أي تغيير.

final class CounterViewModel: ObservableObject {
    @Published var count: Int = 0

    func increment() {
        count += 1
    }
}

خصائص @Published

يؤدي تمييز خاصية باستخدام @Published إلى إصدار إشعار تغيير تلقائيًا كلما عُيّنت قيمتها.

تغذّي كل خاصية @Published ناشر الكائن objectWillChange، ولذلك تعرف View بالضبط متى ينبغي تحديثها.

final class SearchViewModel: ObservableObject {
    @Published var query: String = ""
    @Published var results: [String] = []
}

@StateObject

تخبر @StateObject View بأن تنشئ ViewModel وتملكها. تنشئها SwiftUI مرة واحدة وتحافظ عليها حيةً عبر عمليات إعادة عرض View.

استخدم @StateObject في الموضع الذي تُنشأ فيه ViewModel أول مرة.

struct CounterView: View {
    @StateObject private var viewModel = CounterViewModel()

    var body: some View {
        Button("Count: \(viewModel.count)") {
            viewModel.increment()
        }
    }
}

@ObservedObject

تُستخدم @ObservedObject مع ViewModel أُنشئت في موضع آخر ومُرّرت إلى View. تراقبها View، لكنها لا تملك دورة حياتها.

استخدمها مع واجهات فرعية تستقبل ViewModel من واجهة أب.

struct BadgeView: View {
    @ObservedObject var viewModel: CounterViewModel

    var body: some View {
        Text("Total: \(viewModel.count)")
    }
}

StateObject في مقابل ObservedObject

الفرق الأساسي هو الملكية:

  • @StateObject — تملكها View؛ وتبقى عبر عمليات إعادة العرض
  • @ObservedObject — تُمرّر إلى View؛ ولا تملكها View

قد يؤدي استخدام @ObservedObject حيث ينبغي استخدام @StateObject إلى إعادة إنشاء الكائن وفقدان حالته مع كل تحديث للميزة الأب.

تمرير ViewModel إلى الأسفل

أنشئ ViewModel مرة واحدة باستخدام @StateObject في الميزة الأب، ثم مرّرها إلى الميزات الفرعية التي تضع عليها @ObservedObject.

struct ParentView: View {
    @StateObject private var viewModel = CounterViewModel()

    var body: some View {
        VStack {
            BadgeView(viewModel: viewModel)
            Button("Add") { viewModel.increment() }
        }
    }
}

الارتباطات ثنائية الاتجاه

تحتاج المدخلات مثل حقول النص إلى Binding ثنائي الاتجاه. تنشئ SwiftUI واحدًا من خاصية @Published باستخدام البادئة $ الخاصة بمغلف الخاصية.

struct SearchView: View {
    @StateObject private var viewModel = SearchViewModel()

    var body: some View {
        TextField("Search", text: $viewModel.query)
    }
}

قيادة حالة واجهة المستخدم

يجب أن تستمد View كل ما تعرضه من الخصائص المنشورة. فتنبع مؤشرات التحميل ولافتات الخطأ والمحتوى كلها من حالة ViewModel.

final class FeedViewModel: ObservableObject {
    enum State { case loading, loaded([String]), error(String) }
    @Published var state: State = .loading
}

الاستجابة للحالة

تختار View واجهة المستخدم المناسبة لعرضها وفق حالة ViewModel. لا يوجد كود إجرائي لإظهار العناصر أو إخفائها، بل مجرد ربط تصريحي.

struct FeedView: View {
    @StateObject var viewModel = FeedViewModel()
    var body: some View {
        switch viewModel.state {
        case .loading: ProgressView()
        case .loaded(let items): List(items, id: \.self) { Text($0) }
        case .error(let message): Text(message)
        }
    }
}

إبقاء التحديثات على الخيط الرئيسي

تتطلب SwiftUI إجراء التغيّرات المنشورة على الخيط الرئيسي. وعندما تحدّث ViewModel الحالة بعد عمل غير متزامن، ضع عليها @MainActor لضمان ذلك.

@MainActor
final class ProfileViewModel: ObservableObject {
    @Published var name: String = ""

    func load() async {
        name = await fetchName()
    }
}

مراجعة سريعة

اختبر معرفتك بالارتباطات.

مراجعة

لقد ربطت ViewModels بواجهات View باستخدام ارتباطات SwiftUI:

  • يصدر كل من ObservableObject و@Published إشعارات التغيير
  • تنشئ @StateObject ViewModel وتملكها
  • تراقب @ObservedObject ViewModel مُمرّرة إليها
  • تحافظ @MainActor على التحديثات غير المتزامنة في الخيط الرئيسي

مع تفعيل الارتباطات التفاعلية، تعكس View دائمًا أحدث حالة لـ ViewModel تلقائيًا.

الأسئلة الشائعة

هل درس «ربط نماذج العرض بالعروض» مجاني؟

نعم — نص درس «ربط نماذج العرض بالعروض» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Swift Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Swift Academy 4 دروس في المجموع.

ماذا ستتعلم في «ربط نماذج العرض بالعروض»؟

اربط نماذج العرض باستخدام SwiftUI و Combine. تتمرن على Swift Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Swift Academy؟

لا تُشترط خبرة سابقة. Swift Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «ربط نماذج العرض بالعروض»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Swift Academy هذا؟

نعم. كل درس في Swift Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. نمط MVVM
  2. ربط نماذج العرض بالعروض
  3. نمط Coordinator
  4. اختبار نماذج العرض
← العودة إلى Swift Academy