UIViewController est la classe centrale des applications iOS, gérant l'écran et son contenu. Chaque écran d'iPhone ou d'iPad est géré par un ViewController, qui coordonne l'affichage, le cycle de vie et la navigation. Pour en savoir plus sur l'architecture UIKit, consultez la documentation officielle d'Apple.
Points Clés
UIViewController est une classe du framework UIKit qui gère une hiérarchie de UIView et coordonne l'affichage des données à l'écran. Chaque application iOS contient au moins un ViewController — le contrôleur racine de la fenêtre. Le contrôleur gère les rotations d'écran, les transitions entre les écrans et les événements du cycle de vie.
L'architecture MVC (Model-View-Controller) en iOS est implémentée précisément via UIViewController : le contrôleur reçoit les données du modèle et met à jour la vue. Un ViewController n'est pas un élément visuel — il gère la propriété view, qui contient une hiérarchie de sous-vues. Selon Apple (2026), UIKit contient plus de 40 sous-classes intégrées de UIViewController.
Le premier iPhone SDK (2008) incluait UIViewController avec trois méthodes de cycle de vie. En 18 ans, Apple a ajouté la prise en charge de Container View Controller, des présentations adaptatives, de UIViewControllerTransitioningDelegate pour les animations personnalisées et du mode écran partagé sur iPad. UIViewController reste un composant obligatoire pour les applications UIKit.
Le cycle de vie de UIViewController est une séquence de méthodes appelées par le système lors de la création, de l'affichage et du masquage d'un écran. Comprendre le cycle de vie est crucial : un placement incorrect du code entraîne des fuites de mémoire, des requêtes réseau inutiles et un scintillement de l'interface.
| Méthode | Moment d'appel | Objectif |
|---|---|---|
| viewDidLoad | Une fois, après le chargement de la vue en mémoire | Configuration initiale de l'UI, abonnement Combine |
| viewWillAppear | Avant l'apparition de l'écran | Mise à jour des données, masquer/afficher la barre de navigation |
| viewDidAppear | Après l'apparition de l'écran | Lancer les animations, analyses, mise à jour de la caméra |
| viewWillDisappear | Avant de quitter l'écran | Sauvegarder les brouillons, se désabonner des notifications |
| viewDidDisappear | Après avoir quitté l'écran | Arrêter les processus lourds, libérer les ressources |
Lors du premier affichage de l'écran, la séquence est : init → loadView → viewDidLoad → viewWillAppear → viewDidAppear. Lors de la réapparition (retour d'un autre écran) : viewWillAppear → viewDidAppear. viewDidLoad n'est appelé qu'une fois pendant la durée de vie du contrôleur.
La méthode viewDidLoad est le point principal de configuration de l'interface utilisateur. Elle est appelée après le chargement de la vue en mémoire, lorsque toutes les connexions IBOutlet sont déjà établies. Ici, les éléments d'UI sont créés par programmation, les contraintes sont configurées et les données initiales sont chargées.
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)
}
}Dans SwiftUI, ce code équivaut au corps de la View. Mais UIViewController offre un contrôle total sur le cycle de vie et l'optimisation. bindViewModel utilise Combine pour l'abonnement réactif — les données sont mises à jour automatiquement lorsque le modèle change.
viewWillAppear est appelé chaque fois avant l'apparition de l'écran, même s'il est déjà en mémoire. C'est l'endroit pour mettre à jour les données qui ont pu changer sur un autre écran : recharger une liste, mettre à jour le badge de notifications, configurer la barre de navigation pour un écran spécifique.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Masquer la barre de navigation sur cet écran
navigationController?.setNavigationBarHidden(true, animated: animated)
// Mettre à jour les données lors du retour d'un autre écran
tableView.reloadData()
badgeLabel.text = "\(CartManager.shared.itemCount)"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Analytique : seulement après que l'utilisateur a vu l'écran
AnalyticsService.shared.logScreenView("Profile")
}La différence entre viewDidLoad et viewWillAppear est cruciale : viewDidLoad s'exécute une fois et convient à la configuration statique, viewWillAppear s'exécute chaque fois que l'écran est affiché et convient aux mises à jour dynamiques. Placer des requêtes réseau dans viewDidLoad entraînera l'affichage de données obsolètes lors du retour à l'écran.
Container View Controller est un ViewController qui gère un ou plusieurs ViewControllers enfants. Apple fournit trois conteneurs intégrés : UINavigationController (pile d'écrans), UITabBarController (onglets) et UISplitViewController (maître-détail pour iPad).
UINavigationController organise les transitions dans une pile — push ajoute un écran, pop le supprime. UITabBarController bascule entre les sections indépendantes de l'application. UISplitViewController affiche deux contrôleurs côte à côte sur iPad et un sur iPhone. Un développeur peut créer un conteneur personnalisé via addChild.
// Container View Controller personnalisé
final class ContainerViewController: UIViewController {
private let sidebarVC = SidebarViewController()
private let contentVC = ContentViewController()
override func viewDidLoad() {
super.viewDidLoad()
// Ajout d'un contrôleur enfant
addChild(sidebarVC)
view.addSubview(sidebarVC.view)
sidebarVC.didMove(toParent: self)
addChild(contentVC)
view.addSubview(contentVC.view)
contentVC.didMove(toParent: self)
}
}Le travail correct avec Container View Controller nécessite d'appeler addChild, d'ajouter la vue et didMove(toParent:) dans cet ordre. Lors de la suppression : willMove(toParent: nil), removeFromSuperview, removeFromParent. Violer la séquence entraîne des fuites de mémoire.
Le problème de Massive View Controller survient lorsqu'un UIViewController contient des centaines de lignes de code avec de la logique métier, des requêtes réseau, de la navigation et du code d'UI. Apple reconnaît le problème et recommande MVVM (Model-View-ViewModel) avec Coordinator pour extraire la navigation.
MVVM déplace la logique métier du contrôleur vers une ViewModel. Le Controller lie uniquement la ViewModel à la View via Combine ou un délégué. Coordinator extrait la logique de navigation — création et transition entre les contrôleurs — dans une classe séparée. Cette approche a été adoptée dans les meilleures pratiques d'Apple depuis 2024.
// Coordinator — gestion de la navigation
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)
}
}Le choix entre UIViewController et SwiftUI View dépend de l'année de début du projet, des exigences de personnalisation et de la version minimale d'iOS prise en charge. UIKit avec UIViewController reste la base pour les projets commencés avant 2020 et pour les applications avec une personnalisation profonde de l'interface.
SwiftUI convient aux nouveaux projets avec iOS 17+, aux interfaces standard et aux prototypes. Cependant, les transitions personnalisées, le travail avec la caméra, MapKit, les animations complexes de CALayer nécessitent UIViewController. Apple recommande de combiner les approches via UIHostingController (SwiftUI dans UIKit) et UIViewRepresentable (UIKit dans SwiftUI).
| Scénario | UIKit (UIViewController) | SwiftUI (View) |
|---|---|---|
| Animation personnalisée | Contrôle total via UIViewPropertyAnimator | Limité via Animation |
| Travail avec caméra | AVCaptureSession + UIViewPreview | Via UIViewControllerRepresentable |
| CollectionView | UICollectionView + UICollectionViewLayout | LazyVGrid/LazyHGrid |
| Adaptation iPad | UISplitViewController + UITraitCollection | NavigationSplitView + sizeClass |
| Vitesse de développement | Plus lent (disposition manuelle) | Plus rapide (déclaratif) |
Questions Fréquentes
UIViewController est un contrôleur qui gère l'écran et son cycle de vie. UIView est une vue qui affiche du contenu. Un ViewController contient une hiérarchie de UIViews mais n'est pas lui-même un élément visuel. Un contrôleur gère plusieurs vues.
Massive View Controller est un anti-patron où UIViewController contient trop de logique : données, navigation, requêtes réseau, animation. La solution consiste à extraire le code dans des services séparés, des coordinateurs et une ViewModel (MVVM).
Quatre façons : via une propriété dans prepare(for:sender:) (Segue), via un délégué (Delegate), via une fermeture (Closure), via un service partagé. Pour un couplage faible, utilisez Coordinator + Delegate ou Combine.
Container View Controller est un contrôleur qui gère des ViewControllers enfants. Exemples : UINavigationController, UITabBarController, UISplitViewController. Le contrôleur parent ajoute des enfants via addChild, bascule entre eux et gère leur disposition.
UIViewController — pour les animations personnalisées complexes, le travail avec caméra, les cartes, la vidéo, UICollectionView avec disposition personnalisée. SwiftUI View — pour les interfaces standard sur iOS 13+. La combinaison via UIHostingController est acceptable.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi