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 | Веднъж, след зареждане на view в паметта | Начална настройка на UI, абонамент за Combine |
| viewWillAppear | Преди появата на екрана | Актуализиране на данни, скриване/показване на navigation bar |
| viewDidAppear | След появата на екрана | Стартиране на анимации, аналитика, актуализиране на камера |
| viewWillDisappear | Преди напускане на екрана | Запазване на чернови, отписване от известия |
| viewDidDisappear | След напускане на екрана | Спиране на тежки процеси, освобождаване на ресурси |
При първото показване на екрана: init → loadView → viewDidLoad → viewWillAppear → viewDidAppear. При повторна поява (връщане от друг екран): viewWillAppear → viewDidAppear. viewDidLoad се извиква само веднъж по време на живота на контролера.
Методът viewDidLoad — основната точка за настройка на потребителския интерфейс. Извиква се след зареждане на view в паметта, когато всички IBOutlet вече са свързани. Тук се създават елементи на UI програмно, конфигурират се ограничения, зареждат се начални данни.
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 се извиква всеки път преди появата на екрана, дори ако вече е бил в паметта. Това е мястото за актуализиране на данни, които може да са се променили на друг екран: презареждане на списък, актуализиране на брояча на известия, конфигуриране на navigation bar за конкретен екран.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Скриваме navigation bar на този екран
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 (master-detail за 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, добавяне на view и didMove(toParent:) в този ред. При премахване — willMove(toParent: nil), removeFromSuperview, removeFromParent. Нарушаването на реда води до изтичане на памет.
Проблемът Massive View Controller — когато UIViewController съдържа стотици редове код с бизнес логика, мрежови заявки, навигация и UI код. 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 |
| Скорост на разработка | По-бавна (ръчен layout) | По-бърза (декларативен) |
Често задавани въпроси
UIViewController — контролер, който управлява екрана и неговия жизнен цикъл. UIView — изглед, който показва съдържание. ViewController съдържа UIView йерархия, но сам по себе си не е визуален елемент. Един контролер управлява множество изгледи.
Massive View Controller — анти-модел, когато UIViewController съдържа твърде много логика: данни, навигация, мрежови заявки, анимации. Решение — отделяне на код в отделни услуги, координатори и ViewModel (MVVM).
Четири начина: чрез свойство при prepare(for:sender:) (Segue), чрез делегат (Delegate), чрез затваряне (Closure), чрез споделена услуга. За слабо свързване се използва Coordinator + Delegate или Combine.
Container View Controller — контролер, който управлява подчинени ViewController. Примери: UINavigationController, UITabBarController, UISplitViewController. Родителският контролер добавя подчинени чрез addChild, превключва между тях и управлява техния layout.
UIViewController — за сложни персонализирани анимации, работа с камера, карта, видео, UICollectionView с персонализиран layout. SwiftUI View — за стандартни интерфейси iOS 13+. Комбинирането чрез UIHostingController е позволено.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също