UIViewController هي الفئة المركزية لتطبيقات iOS، التي تدير الشاشة ومحتوياتها. كل شاشة iPhone أو iPad تُدار بواسطة ViewController واحد، ينسق العرض ودورة الحياة والتنقل. اقرأ المزيد عن بنية UIKit في الوثائق الرسمية لـ Apple.
النقاط الرئيسية
UIViewController هي فئة من إطار عمل UIKit تدير تسلسلاً هرمياً لـ UIView وتنسق عرض البيانات على الشاشة. كل تطبيق iOS يحتوي على ViewController واحد على الأقل — وحدة التحكم الجذرية للنافذة. تتعامل وحدة التحكم مع تدوير الشاشة والانتقالات بين الشاشات وأحداث دورة الحياة.
بنية MVC (Model-View-Controller) في iOS تُنفذ تحديداً عبر UIViewController: تتلقى وحدة التحكم البيانات من النموذج وتحدّث العرض. ViewController ليس عنصراً مرئياً — فهو يدير الخاصية view التي تحتوي على تسلسل هرمي من subview. وفقاً لـ Apple (2026)، يحتوي UIKit على أكثر من 40 فئة فرعية مدمجة من UIViewController.
أول iPhone SDK (2008) تضمن UIViewController مع ثلاث طرق لدورة الحياة. على مدى 18 عاماً، أضافت Apple دعماً لـ Container View Controller والعروض التكيفية وUIViewControllerTransitioningDelegate للرسوم المتحركة المخصصة ووضع الشاشة المقسمة على iPad. UIViewController لا يزال مكوناً إلزامياً لتطبيقات UIKit.
دورة حياة UIViewController هي سلسلة من الطرق التي يستدعيها النظام عند إنشاء شاشة وعرضها وإخفائها. فهم دورة الحياة أمر بالغ الأهمية: وضع الكود بشكل غير صحيح يؤدي إلى تسرب الذاكرة وطلبات شبكة غير ضرورية ووميض في الواجهة.
| الطريقة | لحظة الاستدعاء | الغرض |
|---|---|---|
| viewDidLoad | مرة واحدة، بعد تحميل العرض في الذاكرة | إعداد واجهة المستخدم الأولي، الاشتراك في Combine |
| viewWillAppear | قبل ظهور الشاشة | تحديث البيانات، إخفاء/إظهار شريط التنقل |
| viewDidAppear | بعد ظهور الشاشة | بدء الرسوم المتحركة، التحليلات، تحديث الكاميرا |
| viewWillDisappear | قبل مغادرة الشاشة | حفظ المسودات، إلغاء الاشتراك في الإشعارات |
| viewDidDisappear | بعد مغادرة الشاشة | إيقاف العمليات الثقيلة، تحرير الموارد |
في أول عرض للشاشة، التسلسل هو: init ← loadView ← viewDidLoad ← viewWillAppear ← viewDidAppear. عند الظهور مرة أخرى (العودة من شاشة أخرى): viewWillAppear ← viewDidAppear. viewDidLoad يُستدعى مرة واحدة فقط طوال عمر وحدة التحكم.
طريقة viewDidLoad هي النقطة الرئيسية لإعداد واجهة المستخدم. تُستدعى بعد تحميل العرض في الذاكرة، عندما تكون جميع اتصالات IBOutlet قد تم ربطها بالفعل. هنا تُنشأ عناصر واجهة المستخدم برمجياً، وتُضبط القيود (constraints)، وتُحمل البيانات الأولية.
final class ProfileViewController: UIViewController {
private let tableView = UITableView()
private let viewModel = ProfileViewModel()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
bindViewModel()
}
private func setupUI() {
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
tableView.register(ProfileCell.self,
forCellReuseIdentifier: ProfileCell.reuseId)
}
private func bindViewModel() {
viewModel.$user
.receive(on: DispatchQueue.main)
.sink { [weak self] user in
self?.title = user.name
}
.store(in: &cancellables)
}
}في SwiftUI، هذا الكود يعادل جسم View. لكن UIViewController يمنح تحكماً كاملاً في دورة الحياة والتحسين. bindViewModel يستخدم Combine للاشتراك التفاعلي — يتم تحديث البيانات تلقائياً عندما يتغير النموذج.
viewWillAppear تُستدعى في كل مرة قبل ظهور الشاشة، حتى لو كانت موجودة بالفعل في الذاكرة. هذا هو المكان المناسب لتحديث البيانات التي قد تغيرت على شاشة أخرى: إعادة تحميل القائمة، تحديث شارة الإشعارات، ضبط شريط التنقل لشاشة معينة.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// إخفاء شريط التنقل في هذه الشاشة
navigationController?.setNavigationBarHidden(true, animated: animated)
// تحديث البيانات عند العودة من شاشة أخرى
tableView.reloadData()
badgeLabel.text = "\(CartManager.shared.itemCount)"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// التحليلات: فقط بعد أن رأى المستخدم الشاشة
AnalyticsService.shared.logScreenView("Profile")
}الفرق بين viewDidLoad وviewWillAppear جوهري: viewDidLoad يُنفذ مرة واحدة ومناسب للإعداد الثابت، viewWillAppear يُنفذ في كل مرة تُعرض فيها الشاشة ومناسب للتحديثات الديناميكية. وضع طلبات الشبكة في viewDidLoad سيؤدي إلى عرض بيانات قديمة عند العودة إلى الشاشة.
Container View Controller هو ViewController يدير ViewController فرعياً واحداً أو أكثر. توفر Apple ثلاثة حاويات مدمجة: UINavigationController (كومة شاشات)، UITabBarController (علامات تبويب)، وUISplitViewController (سيد-تفصيل لـ iPad).
UINavigationController ينظم الانتقالات في كومة — push يضيف شاشة، pop يزيلها. UITabBarController يتبدل بين الأقسام المستقلة للتطبيق. UISplitViewController يعرض وحدتي تحكم جنباً إلى جنب على iPad وواحدة على iPhone. يمكن للمطور إنشاء حاوية مخصصة عبر addChild.
// Container View Controller مخصص
final class ContainerViewController: UIViewController {
private let sidebarVC = SidebarViewController()
private let contentVC = ContentViewController()
override func viewDidLoad() {
super.viewDidLoad()
// إضافة وحدة تحكم فرعية
addChild(sidebarVC)
view.addSubview(sidebarVC.view)
sidebarVC.didMove(toParent: self)
addChild(contentVC)
view.addSubview(contentVC.view)
contentVC.didMove(toParent: self)
}
}العمل الصحيح مع Container View Controller يتطلب استدعاء addChild وإضافة العرض وdidMove(toParent:) بهذا الترتيب. عند الإزالة: willMove(toParent: nil) وremoveFromSuperview وremoveFromParent. مخالفة التسلسل تؤدي إلى تسرب الذاكرة.
مشكلة Massive View Controller تحدث عندما يحتوي UIViewController على مئات الأسطر من الكود مع منطق الأعمال وطلبات الشبكة والتنقل وكود واجهة المستخدم. تدرك Apple المشكلة وتوصي بـ MVVM (Model-View-ViewModel) مع Coordinator لإخراج التنقل.
MVVM ينقل منطق الأعمال من وحدة التحكم إلى ViewModel. Controller فقط يربط ViewModel بـ View عبر Combine أو المفوض. Coordinator يستخرج منطق التنقل — إنشاء والانتقال بين وحدات التحكم — في فئة منفصلة. تم اعتماد هذا النهج في أفضل ممارسات Apple منذ 2024.
// Coordinator — إدارة التنقل
protocol Coordinator {
var childCoordinators: [Coordinator] { get set }
func start()
}
final class MainCoordinator: Coordinator {
var childCoordinators = [Coordinator]()
private let navigationController: UINavigationController
init(navigationController: UINavigationController) {
self.navigationController = navigationController
}
func start() {
let vc = ListViewController()
vc.didSelectItem = { [weak self] item in
self?.showDetail(item)
}
navigationController.pushViewController(vc, animated: false)
}
private func showDetail(_ item: Item) {
let vc = DetailViewController(item: item)
navigationController.pushViewController(vc, animated: true)
}
}الاختيار بين UIViewController وSwiftUI View يعتمد على سنة بدء المشروع ومتطلبات التخصيص والحد الأدنى من إصدار iOS المدعوم. يبقى UIKit مع UIViewController الأساس للمشاريع التي بدأت قبل 2020 وللتطبيقات ذات التخصيص العميق للواجهة.
SwiftUI مناسب للمشاريع الجديدة مع iOS 17+ والواجهات القياسية والنماذج الأولية. ومع ذلك، تتطلب الانتقالات المخصصة والعمل مع الكاميرا وMapKit والرسوم المتحركة المعقدة لـ CALayer استخدام UIViewController. توصي Apple بالجمع بين النهجين عبر UIHostingController (SwiftUI داخل UIKit) وUIViewRepresentable (UIKit داخل SwiftUI).
| السيناريو | UIKit (UIViewController) | SwiftUI (View) |
|---|---|---|
| رسوم متحركة مخصصة | تحكم كامل عبر UIViewPropertyAnimator | محدود عبر Animation |
| العمل مع الكاميرا | AVCaptureSession + UIViewPreview | عبر UIViewControllerRepresentable |
| CollectionView | UICollectionView + UICollectionViewLayout | LazyVGrid/LazyHGrid |
| تكيف iPad | UISplitViewController + UITraitCollection | NavigationSplitView + sizeClass |
| سرعة التطوير | أبطأ (تخطيط يدوي) | أسرع (تصريحي) |
الأسئلة الشائعة
UIViewController هو وحدة تحكم تدير الشاشة ودورة حياتها. UIView هو عرض يعرض المحتوى. ViewController يحتوي على تسلسل هرمي من UIViews لكنه ليس عنصراً مرئياً بحد ذاته. وحدة تحكم واحدة تدير عروضاً متعددة.
Massive View Controller هو نمط معاكس حيث يحتوي UIViewController على الكثير من المنطق: البيانات والتنقل وطلبات الشبكة والرسوم المتحركة. الحل هو استخراج الكود إلى خدمات منفصلة ومنسقين وViewModel (MVVM).
أربع طرق: عبر خاصية في prepare(for:sender:) (Segue)، عبر مفوض (Delegate)، عبر إغلاق (Closure)، عبر خدمة مشتركة. للاقتران الضعيف، استخدم Coordinator + Delegate أو Combine.
Container View Controller هو وحدة تحكم تدير ViewControllers فرعية. أمثلة: UINavigationController وUITabBarController وUISplitViewController. وحدة التحكم الأم تضيف أطفالاً عبر addChild وتتبدل بينهم وتدير تخطيطهم.
UIViewController — للرسوم المتحركة المخصصة المعقدة والعمل مع الكاميرا والخرائط والفيديو وUICollectionView مع تخطيط مخصص. SwiftUI View — للواجهات القياسية على iOS 13+. الجمع عبر UIHostingController مقبول.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.