MVC (Model-View-Controller) هو نمط معماري يقسم التطبيق إلى ثلاثة مكونات: Model مسؤول عن البيانات ومنطق الأعمال، View مسؤول عن واجهة المستخدم، Controller مسؤول عن معالجة الإدخال والتنسيق بين Model وView. في iOS، يتم تنفيذ MVC عبر UIViewController، في Android — عبر Activity وFragment. يظل MVC النمط الأساسي الذي بُني عليه MVVM وMVP وClean Architecture. اقرأ المزيد على MVC in Cocoa Core.
النقاط الرئيسية
MVC (Model-View-Controller) هو نمط معماري اقترحه Trygve Reenskaug في عام 1979 للغة Smalltalk-80. يقسم النمط التطبيق إلى ثلاث طبقات: Model يحتوي على البيانات ومنطق الأعمال، View مسؤول عن العرض، Controller يعالج إدخال المستخدم ويحدث Model وView. فصل المسؤوليات يسمح بتغيير كل طبقة بشكل مستقل — على سبيل المثال، استبدال View من UIKit إلى SwiftUI دون تغيير منطق الأعمال في Model.
تفاعل المكونات في MVC يتبع دورة: يتفاعل المستخدم مع View → Controller يستقبل الحدث → Controller يحدث Model → Model يخطر Controller بالتغييرات → Controller يحدث View. في التطبيق الكلاسيكي، يستخدم Model نمط Observer: عندما تتغير البيانات، يرسل Model إشعارات، يشترك Controller ويحدث View. في تطبيق Apple، يؤدي Key-Value Observing (KVO) أو NotificationCenter هذه المهمة.
| المكون | المسؤولية | مثال في iOS | مثال في Android |
|---|---|---|---|
| Model | البيانات، منطق الأعمال، الشبكة | Struct User, CoreData | Data class, Repository |
| View | عرض UI | Storyboard, XIB, UIView | XML layout, Jetpack Compose |
| Controller | معالجة الإدخال، التنسيق | UIViewController | Activity, Fragment |
MVC في تطوير الأجهزة المحمولة الحديث يستخدم أقل مما كان عليه قبل 10 سنوات، لكنه يظل ضرورياً للفهم. توصي Apple باستخدام MVC للشاشات البسيطة في تطبيقات UIKit. لا توصي Google باستخدام MVC النقي لـ Android — الوثائق الرسمية تقترح MVVM مع Jetpack. ومع ذلك، فإن معرفة MVC ضرورية للعمل مع المشاريع القديمة ولفهم تطور الأنماط المعمارية.
Apple MVC هو تطبيق مخصص للنمط مدمج في UIKit. يعمل UIViewController كـ Controller: يدير دورة حياة الشاشة (viewDidLoad, viewWillAppear, viewDidDisappear)، يعالج اللمسات وإجراءات المستخدم، يحدث View عبر IBOutlets. يتم إنشاء View في Interface Builder (storyboard أو XIB) أو برمجياً. Model — أي كائنات بيانات: خدمات الشبكة، أكوام CoreData، هياكل Swift.
final class UserViewController: UIViewController {
// View (عبر storyboard outlet)
@IBOutlet private var nameLabel: UILabel!
@IBOutlet private var emailLabel: UILabel!
// Model
private let userService = UserService()
override func viewDidLoad() {
super.viewDidLoad()
loadUser()
}
private func loadUser() {
userService.fetchUser { [weak self] user in
// Controller يحدث View
self?.nameLabel.text = user.name
self?.emailLabel.text = user.email
}
}
}
مشكلة Apple MVC — View وController مرتبطان بإحكام. يدير UIViewController كلاً من View والمنطق في وقت واحد. يخزن Storyboard View في XML، لكن وحدة التحكم لها مراجع مباشرة لعناصر UI عبر IBOutlets. هذا ينتهك مبدأ المسؤولية الواحدة: وحدة التحكم مسؤولة عن دورة الحياة، المفوضين، مصدر البيانات، target-action والرسوم المتحركة. نتيجة لذلك، تحتوي شاشة تطبيق iOS القياسية على 200–500 سطر في وحدة التحكم.
دورة حياة ViewController — توفر Apple 6 طرق لدورة الحياة: loadView (إنشاء View يدوياً)، viewDidLoad (بعد تحميل View في الذاكرة)، viewWillAppear (قبل الظهور على الشاشة)، viewDidAppear (بعد الرسوم المتحركة)، viewWillDisappear (قبل مغادرة الشاشة)، viewDidDisappear (بعد المغادرة). كل طريقة مكان لوضع المنطق في MVC. استخدام هذه الطرق لمنطق الأعمال يسرع نمو وحدة التحكم.
Android MVC — Activity وFragment يعملان كـ Controller، ملفات XML layout كـ View، أي فئة POJO مع بيانات كـ Model. يدير Activity دورة حياة الشاشة: onCreate، onStart، onResume، onPause، onStop، onDestroy. Fragment هو شاشة فرعية داخل Activity بدورة حياة خاصة به. View (XML) منفصلة عن Controller ويتم تحميلها عبر setContentView أو LayoutInflater. Model — المستودعات، قواعد البيانات، استدعاءات الشبكة.
class UserActivity : AppCompatActivity() {
// View عبر XML layout
private lateinit var binding: ActivityUserBinding
// Model
private val userRepository = UserRepository()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityUserBinding.inflate(layoutInflater)
setContentView(binding.root)
loadUser()
}
private fun loadUser() {
userRepository.getUser { user ->
runOnUiThread {
binding.nameText.text = user.name
binding.emailText.text = user.email
}
}
}
}
Android ViewBinding وDataBinding — أدوات حديثة تقلل الاقتران بين Controller وView. يولد ViewBinding فئة بمراجع مباشرة لـ Views من XML، مما يلغي findViewById. يضيف DataBinding إمكانية ربط البيانات بـ UI في ترميز XML عبر @{user.name}. DataBinding هو خطوة نحو MVVM، لأنه يسمح بتمرير البيانات من Model إلى View بدون كود في Activity. توصي Google باستخدام DataBinding لجميع المشاريع الجديدة.
دورة حياة Android أكثر تعقيداً من iOS: يمكن تدمير Activity وإعادة إنشائها عند تدوير الشاشة، نقص الذاكرة، أو تغيير التكوين. في MVC النقي، تحتوي وحدة التحكم (Activity) على منطق يُفقد عند التدمير. هذا يتطلب حفظ الحالة عبر onSaveInstanceState أو ViewModel من Jetpack، مما يتجاوز MVC النقي ويقرب الهندسة المعمارية من MVVM.
Massive View Controller هو مصطلح يصف المشكلة الرئيسية لـ MVC في تطوير الأجهزة المحمولة. تتحمل وحدة التحكم في iOS وAndroid مسؤوليات كثيرة جداً: معالجة الإدخال، التحقق من صحة البيانات، التفاعل مع الشبكة، التنقل، التخزين المؤقت، الرسوم المتحركة، إدارة دورة الحياة. نتيجة لذلك، تنمو وحدة التحكم إلى 500–2000 سطر من الكود، مما يجعلها صعبة القراءة والاختبار والصيانة.
أسباب Massive View Controller — تشجع بنية UIKit وAndroid Framework وضع المنطق في وحدة التحكم. استدعاءات الشبكة، معالجة JSON، التنقل — كل هذا يذهب بشكل طبيعي إلى Activity أو UIViewController لأنهما يمتلكان حق الوصول إلى دورة الحياة وUI. يجب على المطور استخراج المنطق بوعي إلى فئات منفصلة (Service, Manager, Interactor)، مما يتطلب الانضباط وفهم المبادئ المعمارية.
| مشكلة MVC | الوصف | الحل |
|---|---|---|
| اقتران قوي | Controller يعرف View وModel | MVVM — ViewModel لا يعرف View |
| صعوبة الاختبار | Controller يعتمد على UIKit/Android | استخراج المنطق إلى خدمات |
| دورة الحياة | الحالة تُفقد عند التدوير | ViewModel من Jetpack/SwiftUI |
| نقص التنقل | Controller يدير الانتقالات | نمط Coordinator, Router |
اختبار MVC — Model يُختبر بشكل معزول باختبارات الوحدة. Controller يصعب اختباره بسبب الاعتماد على UIKit/UIFoundation. لا يسمح XCTest بإنشاء UIViewController بدون نافذة عرض. بالنسبة لـ Android، يحل ActivityTestRule وRobolectric المشكلة جزئياً، لكن الاختبارات بطيئة. View عادة لا تُختبر باختبارات الوحدة — للـ UI تُستخدم اختبارات لقطات الشاشة واختبارات UI (XCUITest, Espresso).
متى يكون MVC مبرراً — الشاشات البسيطة بعنصر أو عنصرين (شاشة تسجيل الدخول، الملف الشخصي، الإعدادات). النماذج الأولية وMVP للتحقق من الفرضيات — MVC أسرع في الكتابة بدون طبقات إضافية. المشاريع ذات قاعدة الكود الصغيرة حتى 10–15 شاشة. في المشاريع المعقدة، يؤدي MVC إلى تراكم الديون الفنية ويتطلب إعادة هيكلة كل 6–12 شهراً.
MVC vs MVVM — الفرق الرئيسي: في MVVM، يُستبدل Controller بـ ViewModel الذي ليس لديه مرجع لـ View. تُنقل البيانات عبر Observable (SwiftUI)، LiveData/StateFlow (Android) أو Combine/RxSwift. ViewModel قابل للاختبار باختبارات الوحدة بدون تبعيات UI. توصي Apple باستخدام MVVM مع SwiftUI منذ 2019، Google — MVVM مع LiveData/Flow كبنية Android الرسمية. يتطلب MVVM كوداً أكثر للربط لكنه يحسن قابلية الاختبار بشكل كبير.
MVC vs MVP — في MVP (Model-View-Presenter)، Presenter هو طبقة قابلة للاختبار تستقبل View عبر واجهة. على عكس MVC حيث يدير Controller View مباشرة عبر UIKit، لا يعتمد Presenter على الإطار — يعمل عبر تجريد ViewInterface. كان MVP شائعاً في تطوير Android قبل Jetpack ويُستخدم في المشاريع القديمة. Presenter يعيش أطول من Activity ويحافظ على الحالة عند تدوير الشاشة.
MVC vs Clean Architecture — Clean Architecture يضيف طبقات: Use Cases (Interactors)، Entities، Gateways وRepository. يبقى MVC في طبقة Presentation، لكن منطق الأعمال يُنقل إلى طبقة Domain مع Use Cases. يحل Clean Architecture مشكلة Massive View Controller بشكل جذري — Controller يحتوي فقط على استدعاءات Use Cases وتحديثات View. العيب هو زيادة كبيرة في عدد الفئات والملفات، وهو ما يبرر للمشاريع التي تحتوي على 50+ شاشة.
// MVC في iOS: Controller يحتوي على كل شيء
class OrderViewController: UIViewController {
func placeOrder() {
// التحقق + الشبكة + تحديث UI
guard Validation.isValid(total) else { return }
NetworkService.shared.submit(order) { [weak self] result in
self?.handleResult(result)
}
}
}
// MVVM: المنطق في ViewModel
class OrderViewModel: ObservableObject {
@Published var state: OrderState = .idle
func placeOrder() { /* منطق الأعمال */ }
}
اختيار المعمارية يعتمد على حجم الفريق، نطاق المشروع وقابلية الاختبار المطلوبة. لفريق من 1–2 مطورين ومشروع يصل إلى 20 شاشة، يعمل MVVM بشكل جيد. لفريق كبير من 5+ مطورين ومشروع به 50+ شاشة — Clean Architecture بهيكل معياري. MVC يظل ذا صلة لفهم تطور المعماريات، لصيانة المشاريع القديمة، وللشاشات البسيطة في UIKit بدون منطق أعمال معقد.
الأسئلة الشائعة
المشكلة الرئيسية هي Massive View Controller. في iOS، يدير UIViewController كل شيء: معالجة الإدخال، تحديث View، الشبكات، التنقل ودورة الحياة. في Android، يؤدي Activity/Fragment وظائف مماثلة. نتيجة لذلك، تنمو وحدة التحكم لآلاف الأسطر من الكود، ويصعب اختبارها وصيانتها، منتهكة مبدأ المسؤولية الواحدة.
في MVC، يحدث Controller View مباشرة ويعالج إدخال المستخدم. في MVVM، يؤدي ViewModel دور Controller، وليس لديه مرجع لـ View — تُنقل البيانات عبر آليات الربط. MVVM أسهل في الاختبار لأن ViewModel لا يعتمد على UIKit أو Android Framework. توصي Apple باستخدام MVVM مع SwiftUI، Google توصي باستخدام MVVM مع Jetpack Compose.
نعم، يظل MVC نمطاً عملياً للشاشات البسيطة والنماذج الأولية. توصي Apple باستخدام MVC لتطبيقات UIKit ذات الشاشات البسيطة. للمشاريع المعقدة ذات الشاشات المتعددة وطلبات الشبكة والتخزين المؤقت، من الأفضل اختيار MVVM أو VIPER أو Clean Architecture. يُنصح المطورون المبتدئون بإتقان MVC قبل تعلم أنماط أكثر تعقيداً.
Model يُختبر بشكل معزول — هذه كائنات بيانات ومنطق أعمال عادية. Controller يصعب اختباره بسبب الاعتماد على UIKit أو Android Framework. يُنصح باستخراج منطق الأعمال من Controller إلى خدمات أو interactors منفصلة تُختبر باختبارات الوحدة. View عادة لا تُختبر باختبارات الوحدة — تُستخدم اختبارات UI واختبارات لقطات الشاشة.
على iOS — MVVM مع SwiftUI وCombine، معيار Apple منذ 2019. على Android — MVVM مع LiveData أو StateFlow، موصى به رسمياً من Google. للمشاريع الكبيرة بفرق من 5+ مطورين — Clean Architecture مع VIPER على iOS أو Clean Architecture على Android مع فصل وحدات حسب الميزات. للمشاريع القديمة مع MVC — إعادة هيكلة تدريجية مع استخراج المنطق إلى خدمات منفصلة.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.