UIViewController — clasa centrală a aplicației iOS, care gestionează ecranul și conținutul său. Fiecare ecran al iPhone-ului sau iPad-ului este gestionat de un ViewController care coordonează afișarea, ciclul de viață și navigația. Citiți mai multe despre arhitectura UIKit în documentația oficială Apple.
Puncte principale
UIViewController — o clasă din framework-ul UIKit care gestionează ierarhia UIView și coordonează afișarea datelor pe ecran. Fiecare aplicație iOS conține cel puțin un ViewController — controlerul rădăcină al ferestrei. Controlerul gestionează rotațiile ecranului, tranzițiile între ecrane și evenimentele ciclului de viață.
Arhitectura MVC (Model-View-Controller) în iOS este implementată exact prin UIViewController: controlerul primește date de la model și actualizează vizualizarea. ViewController nu este un element vizual — gestionează proprietatea view, care conține ierarhia subview-urilor. Conform datelor Apple (2026), UIKit conține peste 40 de subclase încorporate de UIViewController.
Primul iPhone SDK (2008) includea UIViewController cu trei metode ale ciclului de viață. În 18 ani, Apple a adăugat suport pentru Container View Controller, prezentări adaptive, UIViewControllerTransitioningDelegate pentru animații personalizate și modul ecran divizat pe iPad. UIViewController rămâne o componentă obligatorie pentru aplicațiile UIKit.
Ciclul de viață al UIViewController — o secvență de metode apelate de sistem la crearea, afișarea și ascunderea ecranului. Înțelegerea ciclului de viață este critică: plasarea incorectă a codului duce la scurgeri de memorie, solicitări de rețea inutile și pâlpâirea interfeței.
| Metodă | Momentul apelării | Destinație |
|---|---|---|
| viewDidLoad | O dată, după încărcarea view în memorie | Configurare inițială UI, abonare Combine |
| viewWillAppear | Înainte de apariția ecranului | Actualizare date, ascundere/afișare navigation bar |
| viewDidAppear | După apariția ecranului | Pornire animații, analitică, actualizare cameră |
| viewWillDisappear | Înainte de părăsirea ecranului | Salvare schițe, dezabonare de la notificări |
| viewDidDisappear | După părăsirea ecranului | Oprire procese grele, eliberare resurse |
La prima afișare a ecranului, secvența: init → loadView → viewDidLoad → viewWillAppear → viewDidAppear. La reapariție (revenire de pe alt ecran): viewWillAppear → viewDidAppear. viewDidLoad este apelată doar o dată pe durata de viață a controlerului.
Metoda viewDidLoad — punctul principal de configurare a interfeței de utilizator. Apelată după încărcarea view în memorie, când toate IBOutlet-urile sunt deja conectate. Aici sunt create elementele UI programatic, configurate constrângerile, încărcate datele inițiale.
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)
}
}În SwiftUI, acest cod este echivalentul corpului View. Dar UIViewController oferă control complet asupra ciclului de viață și optimizării. bindViewModel folosește Combine pentru abonare reactivă — datele se actualizează automat la schimbarea modelului.
viewWillAppear este apelată de fiecare dată înainte de apariția ecranului, chiar dacă acesta era deja în memorie. Acesta este locul pentru actualizarea datelor care s-ar fi putut schimba pe un alt ecran: reîncărcarea listei, actualizarea contorului de notificări, configurarea navigation bar pentru ecranul specific.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Ascunde bara de navigare pe acest ecran
navigationController?.setNavigationBarHidden(true, animated: animated)
// Actualizează datele la revenirea de pe alt ecran
tableView.reloadData()
badgeLabel.text = "\(CartManager.shared.itemCount)"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Analitică: doar după ce utilizatorul a văzut ecranul
AnalyticsService.shared.logScreenView("Profile")
}Diferența dintre viewDidLoad și viewWillAppear este critică: viewDidLoad se execută o dată și este potrivită pentru configurare statică, viewWillAppear — de fiecare dată la afișare, potrivită pentru actualizări dinamice. Plasarea solicitărilor de rețea în viewDidLoad va duce la afișarea datelor învechite la revenirea pe ecran.
Container View Controller — un ViewController care gestionează unul sau mai multe ViewController-uri copil. Apple oferă trei containere încorporate: UINavigationController (stivă de ecrane), UITabBarController (file) și UISplitViewController (master-detail pentru iPad).
UINavigationController organizează tranzițiile într-o stivă — push adaugă un ecran, pop îl elimină. UITabBarController comută între secțiunile independente ale aplicației. UISplitViewController afișează două controlere unul lângă altul pe iPad și unul pe iPhone. Dezvoltatorul poate crea propriul container prin addChild.
// Container View Controller personalizat
final class ContainerViewController: UIViewController {
private let sidebarVC = SidebarViewController()
private let contentVC = ContentViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Adăugarea controlerului copil
addChild(sidebarVC)
view.addSubview(sidebarVC.view)
sidebarVC.didMove(toParent: self)
addChild(contentVC)
view.addSubview(contentVC.view)
contentVC.didMove(toParent: self)
}
}Lucrul corect cu Container View Controller necesită apelarea addChild, adăugarea view și didMove(toParent:) în această ordine. La eliminare — willMove(toParent: nil), removeFromSuperview, removeFromParent. Încălcarea ordinii duce la scurgeri de memorie.
Problema Massive View Controller — când UIViewController conține sute de linii de cod cu logică de afaceri, solicitări de rețea, navigație și cod UI. Apple este conștientă de problemă și recomandă MVVM (Model-View-ViewModel) împreună cu Coordinator pentru separarea navigației.
MVVM mută logica de afaceri din controler în ViewModel. Controller doar conectează ViewModel-ul cu View-ul prin Combine sau delegat. Coordinator separă logica de navigație — crearea și tranzițiile între controlere — într-o clasă separată. Această abordare a fost introdusă în cele mai bune practici Apple din 2024.
// Coordinator — gestionarea navigației
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)
}
}Alegerea între UIViewController și SwiftUI View depinde de anul începerii proiectului, cerințele de personalizare și versiunea minimă de iOS suportată. UIKit cu UIViewController rămâne baza pentru proiectele începute înainte de 2020 și pentru aplicațiile cu personalizare profundă a interfeței.
SwiftUI este potrivit pentru proiecte noi cu iOS 17+, interfețe standard și prototipuri. Totuși, pentru tranziții personalizate, lucru cu camera, MapKit, animații complexe CALayer este necesar UIViewController. Apple recomandă combinarea abordărilor prin UIHostingController (SwiftUI în UIKit) și UIViewRepresentable (UIKit în SwiftUI).
| Scenariu | UIKit (UIViewController) | SwiftUI (View) |
|---|---|---|
| Animație personalizată | Control complet prin UIViewPropertyAnimator | Limitat prin Animation |
| Lucru cu camera | AVCaptureSession + UIViewPreview | Prin UIViewControllerRepresentable |
| CollectionView | UICollectionView + UICollectionViewLayout | LazyVGrid/LazyHGrid |
| Adaptare iPad | UISplitViewController + UITraitCollection | NavigationSplitView + sizeClass |
| Viteză de dezvoltare | Mai lentă (layout manual) | Mai rapidă (declarativ) |
Întrebări frecvente
UIViewController — controler care gestionează ecranul și ciclul său de viață. UIView — vizualizare care afișează conținut. ViewController conține o ierarhie UIView, dar nu este el însuși un element vizual. Un controler gestionează mai multe vizualizări.
Massive View Controller — un anti-pattern când UIViewController conține prea multă logică: date, navigație, solicitări de rețea, animații. Soluția — separarea codului în servicii separate, coordonatori și ViewModel (MVVM).
Patru moduri: prin proprietate la prepare(for:sender:) (Segue), prin delegat (Delegate), prin închidere (Closure), printr-un serviciu comun. Pentru cuplare slabă se utilizează Coordinator + Delegate sau Combine.
Container View Controller — un controler care gestionează ViewController-uri copil. Exemple: UINavigationController, UITabBarController, UISplitViewController. Controlerul părinte adaugă copiii prin addChild, comută între ei și gestionează layout-ul lor.
UIViewController — pentru animații personalizate complexe, lucru cu camera, hartă, video, UICollectionView cu layout personalizat. SwiftUI View — pentru interfețe standard iOS 13+. Combinarea prin UIHostingController este permisă.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și