0Pricing
Swift Academy · درس

نمط MVVM

افصل مسؤوليات العرض ونموذج العرض والنموذج.

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

ما المقصود بـ MVVM؟

اختصار MVVM هو Model-View-ViewModel. وهو نمط معماري يقسّم تطبيقك إلى ثلاث طبقات، لكل منها مسؤولية واضحة واحدة.

  • Model — البيانات وقواعد العمل
  • View — ما يراه المستخدم
  • ViewModel — الجسر الذي يجهّز بيانات Model لـ View

الهدف هو فصل المسؤوليات؛ إذ تتغيّر كل طبقة لسبب يخصّها، بصورة مستقلة عن الطبقات الأخرى.

طبقة Model

تحتوي Model على بياناتك الخام والقواعد التي تحكمها. ولا تعرف شيئًا عن الشاشة أو عن طريقة عرض العناصر.

تكون Models عادةً عبارة عن هياكل بسيطة أو كائنات من النطاق. ويسهل اختبارها لأنها لا تعتمد على واجهة المستخدم.

struct User {
    let id: UUID
    let firstName: String
    let lastName: String
    let isPremium: Bool
}

struct Order {
    let items: [String]
    let total: Decimal
}

طبقة View

تتولى View العرض فقط. ففي SwiftUI تكون عبارة عن هياكل View، وفي UIKit تكون عبارة عن UIViewController والعروض الفرعية التابعة له.

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

struct ProfileView: View {
    @StateObject var viewModel: ProfileViewModel

    var body: some View {
        VStack {
            Text(viewModel.displayName)
            if viewModel.showBadge {
                Text("Premium")
            }
        }
    }
}

طبقة ViewModel

تقع ViewModel بين Model وView. فهي تأخذ بيانات Model الخام وتحولها إلى قيم جاهزة للعرض يمكن لـ View عرضها مباشرة.

كما تكشف عن النوايا (الأساليب) التي تستدعيها View عندما يتفاعل المستخدم.

final class ProfileViewModel: ObservableObject {
    @Published var displayName: String
    @Published var showBadge: Bool

    init(user: User) {
        displayName = user.firstName + " " + user.lastName
        showBadge = user.isPremium
    }
}

لماذا نفصل المسؤوليات؟

عندما تختلط عملية التنسيق والشبكات والعرض داخل view controller، يتحول ذلك الملف إلى كتلة ضخمة يتعذر اختبارها.

وبتقسيم المسؤوليات:

  • يمكن إعادة استخدام Model عبر شاشات متعددة
  • يمكن اختبار ViewModel باختبارات وحدات من دون واجهة مستخدم
  • تبقى View صغيرة وتصريحية

ما الذي ينتمي إلى Model؟

ضع في Model:

  • كيانات النطاق (User، Product)
  • قواعد التحقق الخاصة بالعمل
  • تجريدات التخزين والشبكات (غالبًا عبر خدمات تستدعيها ViewModel)

لا تضع أبدًا نصوص واجهة المستخدم أو الألوان أو التنسيق في Model.

ما الذي ينتمي إلى ViewModel؟

تتعامل ViewModel مع منطق العرض:

  • تنسيق التواريخ والعملات والأسماء في سلاسل نصية للعرض
  • تحديد حالات واجهة المستخدم الظاهرة (التحميل، والخطأ، والفراغ)
  • تنسيق استدعاءات الخدمات وكشف النتائج
final class CartViewModel: ObservableObject {
    @Published var totalText: String = ""

    func update(with order: Order) {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        totalText = formatter.string(from: order.total as NSNumber) ?? "-"
    }
}

ما الذي ينتمي إلى View؟

يجب أن تقتصر View على:

  • ترتيب عناصر واجهة المستخدم وعرضها
  • قراءة الحالة المنشورة من ViewModel
  • تمرير النقرات والإيماءات باستدعاء أساليب ViewModel

إذا وجدت if يقرر قواعد العمل داخل View، فمن المرجح أن ينتمي ذلك المنطق إلى ViewModel.

تدفق البيانات في MVVM

يتدفق البيانات في اتجاه واحد، بينما تتدفق الإجراءات في الاتجاه المعاكس:

  • Model -> ViewModel -> View للبيانات
  • View -> ViewModel لنوايا المستخدم

لا تتحدث View مع Model مباشرةً. ويحافظ ذلك على توجّه الاعتماديات إلى الداخل، نحو نطاقك.

MVVM في مقابل MVC

في MVC التقليدي، يكبر حجم controller غالبًا لأنه يتولى التنسيق والشبكات وربط الواجهة كلها في الوقت نفسه.

يستخرج MVVM منطق العرض هذا إلى ViewModel، تاركًا controller (أو View في SwiftUI) نحيفًا. كما أن ViewModel لا تعتمد على إطار واجهة المستخدم، ولذلك يسهل اختبارها كثيرًا.

جزء متكامل

إليك جزءًا صغيرًا لكنه متكامل من MVVM يربط الطبقات معًا.

struct Account { let balance: Decimal }

final class AccountViewModel: ObservableObject {
    @Published var balanceText: String
    init(account: Account) {
        balanceText = "$" + "\(account.balance)"
    }
}

struct AccountView: View {
    @StateObject var viewModel: AccountViewModel
    var body: some View { Text(viewModel.balanceText) }
}

مراجعة سريعة

اختبر فهمك لمسؤوليات MVVM.

مراجعة

تعلّمت الطبقات الثلاث في MVVM وحدود مسؤولياتها:

  • Model — البيانات الخام وقواعد العمل، من دون واجهة مستخدم
  • ViewModel — منطق العرض والنوايا
  • View — عرض حالة ViewModel فقط

إن إبقاء هذه المسؤوليات منفصلة يجعل شيفرتك قابلة للاختبار وإعادة الاستخدام، ويسهّل فهمها. سنربط في الخطوة التالية ViewModel بـ View باستخدام الارتباطات.

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

هل درس «نمط MVVM» مجاني؟

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

ماذا ستتعلم في «نمط MVVM»؟

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

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

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

كم من الوقت يستغرق درس «نمط MVVM»؟

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

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

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

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

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