الأنماط المعمارية في Swift: من الفوضى إلى النظام
\n\nكل مطور iOS يواجه عاجلاً أم آجلاً السؤال: "كيف أنظم الكود بحيث لا يتحول المشروع إلى فوضى بعد ستة أشهر؟" الإجابة بسيطة — الأنماط المعمارية. في Swift، كما في أي لغة أخرى، يحدد اختيار البنية مدى سهولة صيانة التطبيق واختباره وتوسيعه. اليوم سنحلل ثلاثة من أشهر الأساليب: MVC و MVVM و VIPER. لا نظرية جافة — فقط كود حي ونصائح عملية.
\n\nإذا كنت تكتب بلغة Swift ولكنك لا تزال تستخدم "كل شيء في ملف واحد" — فهذه المقالة لك. هيا بنا!
\n\nMVC (Model-View-Controller) — الكلاسيكية
\n\nMVC هو النمط الذي تضعه Apple كأساس لـ UIKit. يبدو الأمر بسيطًا: Model مسؤول عن البيانات، View مسؤول عن العرض، Controller يربط بينهما. لكن عمليًا، يتحول MVC في iOS غالبًا إلى Massive View Controller — وحدة تحكم تعرف كل شيء، تفعل كل شيء، وتزن آلاف الأسطر.
\n\nومع ذلك، إذا تم الالتزام بالانضباط، فإن MVC يعمل بشكل ممتاز. إليك مثال لتطبيق بسيط لعرض قائمة المستخدمين.
\n\n// Model\nstruct User {\n let name: String\n let email: String\n}\n\n// View (ليس كود UI، بل بروتوكول للتحديث)\nprotocol UserListView: AnyObject {\n func showUsers(_ users: [User])\n func showError(_ error: Error)\n}\n\n// Controller\nclass UserListViewController: UIViewController, UserListView {\n \n @IBOutlet weak var tableView: UITableView!\n private var users: [User] = []\n private let dataService = DataService()\n \n override func viewDidLoad() {\n super.viewDidLoad()\n tableView.dataSource = self\n loadUsers()\n }\n \n func loadUsers() {\n dataService.fetchUsers { [weak self] result in\n switch result {\n case .success(let users):\n self?.showUsers(users)\n case .failure(let error):\n self?.showError(error)\n }\n }\n }\n \n func showUsers(_ users: [User]) {\n self.users = users\n tableView.reloadData()\n }\n \n func showError(_ error: Error) {\n let alert = UIAlertController(title: "خطأ", message: error.localizedDescription, preferredStyle: .alert)\n alert.addAction(UIAlertAction(title: "موافق", style: .default))\n present(alert, animated: true)\n }\n}\n\nextension UserListViewController: UITableViewDataSource {\n func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {\n return users.count\n }\n \n func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {\n let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell", for: indexPath)\n let user = users[indexPath.row]\n cell.textLabel?.text = user.name\n cell.detailTextLabel?.text = user.email\n return cell\n }\n}\n\nإيجابيات MVC:
\n- \n
- البساطة والوضوح — كل مطور جديد يفهمه بسرعة. \n
- دعم أصلي من Apple — لا حاجة لإضافة مكتبات خارجية. \n
- بداية سريعة للمشاريع الصغيرة. \n
سلبيات MVC:
\n- \n
- تصبح وحدات التحكم "ضخمة" ويصعب اختبارها. \n
- صعوبة إعادة استخدام المنطق بين الشاشات المختلفة. \n
- عند نمو المشروع، يتحول الكود إلى معكرونة. \n
الخلاصة: MVC جيد للتطبيقات البسيطة أو النماذج الأولية. إذا كنت تعلم أن المشروع سينمو — فانظر نحو MVVM أو VIPER.
\n\nMVVM (Model-View-ViewModel) — المعيار الحديث
\n\nيحل MVVM المشكلة الرئيسية لـ MVC — يخفف الحمل عن وحدة التحكم. يتم نقل كل منطق الأعمال وإعداد البيانات للعرض إلى ViewModel. View (وحدة التحكم) تشترك فقط في التغييرات