ViewController — l'essenza del controller dello schermo in iOS e il suo Lifecycle

Autore: IT Sectr Pubblicato: 2026-02-22 Tempo di lettura: 7 min

UIViewController è la classe centrale delle applicazioni iOS, che gestisce lo schermo e il suo contenuto. Ogni schermo di iPhone o iPad è gestito da un ViewController, che coordina la visualizzazione, il ciclo di vita e la navigazione. Ulteriori informazioni sull'architettura UIKit sono disponibili nella documentazione ufficiale Apple.

Punti Chiave

  • UIViewController — la classe base per gestire uno schermo in UIKit con il proprio ciclo di vita
  • viewDidLoad — chiamato una volta, punto di inizializzazione dell'UI e sottoscrizione ai dati
  • viewWillAppear — lo schermo sarà presto visibile, aggiornamento dei dati prima della visualizzazione
  • Lifecycle include cinque metodi: viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear
  • Massive View Controller — il principale anti-pattern iOS, risolto tramite MVVM o Coordinator

Cos'è un ViewController?

UIViewController è una classe del framework UIKit che gestisce una gerarchia di UIView e coordina la visualizzazione dei dati sullo schermo. Ogni applicazione iOS contiene almeno un ViewController — il controller principale della finestra. Il controller gestisce le rotazioni dello schermo, le transizioni tra schermi e gli eventi del ciclo di vita.

L'architettura MVC (Model-View-Controller) in iOS è implementata proprio attraverso UIViewController: il controller riceve i dati dal modello e aggiorna la vista. Un ViewController non è un elemento visivo — gestisce la proprietà view, che contiene una gerarchia di subview. Secondo Apple (2026), UIKit contiene più di 40 sottoclassi incorporate di UIViewController.

Il primo iPhone SDK (2008) includeva UIViewController con tre metodi del ciclo di vita. In 18 anni, Apple ha aggiunto il supporto per Container View Controller, presentazioni adattive, UIViewControllerTransitioningDelegate per animazioni personalizzate e la modalità schermo diviso su iPad. UIViewController rimane un componente obbligatorio per le applicazioni UIKit.

Il ciclo di vita di UIViewController

Il ciclo di vita di UIViewController è una sequenza di metodi chiamati dal sistema durante la creazione, la visualizzazione e l'occultamento di uno schermo. Comprendere il Lifecycle è criticamente importante: un posizionamento errato del codice porta a perdite di memoria, richieste di rete non necessarie e sfarfallio dell'interfaccia.

MetodoMomento della chiamataScopo
viewDidLoadUna volta, dopo il caricamento della view in memoriaConfigurazione iniziale dell'UI, sottoscrizione Combine
viewWillAppearPrima che lo schermo appaiaAggiornamento dati, nascondere/mostrare la barra di navigazione
viewDidAppearDopo che lo schermo è apparsoAvviare animazioni, analisi, aggiornamento fotocamera
viewWillDisappearPrima di lasciare lo schermoSalvare bozze, annullare sottoscrizione alle notifiche
viewDidDisappearDopo aver lasciato lo schermoFermare processi pesanti, liberare risorse

Ordine di chiamata all'apparizione dello schermo

Al primo display dello schermo, la sequenza è: init → loadView → viewDidLoad → viewWillAppear → viewDidAppear. Alla riapparizione (ritorno da un altro schermo): viewWillAppear → viewDidAppear. viewDidLoad viene chiamato solo una volta durante la vita del controller.

viewDidLoad, init e configurazione dell'UI

Il metodo viewDidLoad è il punto principale per configurare l'interfaccia utente. Viene chiamato dopo che la view è stata caricata in memoria, quando tutte le connessioni IBOutlet sono già state stabilite. Qui gli elementi UI vengono creati programmaticamente, i vincoli vengono configurati e i dati iniziali vengono caricati.

swift
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)
    }
}

In SwiftUI, questo codice è equivalente al corpo della View. Ma UIViewController offre il controllo completo sul ciclo di vita e l'ottimizzazione. bindViewModel utilizza Combine per la sottoscrizione reattiva — i dati vengono aggiornati automaticamente quando il modello cambia.

viewWillAppear e aggiornamento dei dati

viewWillAppear viene chiamato ogni volta prima che lo schermo appaia, anche se è già in memoria. Questo è il posto per aggiornare i dati che potrebbero essere cambiati su un altro schermo: ricaricare una lista, aggiornare il badge delle notifiche, configurare la barra di navigazione per uno schermo specifico.

swift
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)

    // Nascondere la barra di navigazione su questo schermo
    navigationController?.setNavigationBarHidden(true, animated: animated)

    // Aggiornare i dati al ritorno da un altro schermo
    tableView.reloadData()
    badgeLabel.text = "\(CartManager.shared.itemCount)"
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Analisi: solo dopo che l'utente ha visto lo schermo
    AnalyticsService.shared.logScreenView("Profile")
}

La differenza tra viewDidLoad e viewWillAppear è critica: viewDidLoad viene eseguito una volta ed è adatto per la configurazione statica, viewWillAppear viene eseguito ogni volta che lo schermo viene visualizzato ed è adatto per aggiornamenti dinamici. Posizionare richieste di rete in viewDidLoad comporterà la visualizzazione di dati obsoleti al ritorno sullo schermo.

Container View Controller: UINavigationController e UITabBarController

Container View Controller è un ViewController che gestisce uno o più ViewController figli. Apple fornisce tre contenitori incorporati: UINavigationController (pila di schermi), UITabBarController (schede) e UISplitViewController (master-detail per iPad).

UINavigationController organizza le transizioni in una pila — push aggiunge uno schermo, pop lo rimuove. UITabBarController passa da una sezione all'altra dell'applicazione. UISplitViewController mostra due controller affiancati su iPad e uno su iPhone. Uno sviluppatore può creare un contenitore personalizzato tramite addChild.

swift
// Container View Controller personalizzato
final class ContainerViewController: UIViewController {

    private let sidebarVC = SidebarViewController()
    private let contentVC = ContentViewController()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Aggiunta di un controller figlio
        addChild(sidebarVC)
        view.addSubview(sidebarVC.view)
        sidebarVC.didMove(toParent: self)

        addChild(contentVC)
        view.addSubview(contentVC.view)
        contentVC.didMove(toParent: self)
    }
}

Il lavoro corretto con Container View Controller richiede di chiamare addChild, aggiungere la view e didMove(toParent:) in quest'ordine. Durante la rimozione: willMove(toParent: nil), removeFromSuperview, removeFromParent. Violare la sequenza porta a perdite di memoria.

Risolvere Massive View Controller con MVVM e Coordinator

Il problema del Massive View Controller si verifica quando un UIViewController contiene centinaia di righe di codice con logica di business, richieste di rete, navigazione e codice UI. Apple riconosce il problema e raccomanda MVVM (Model-View-ViewModel) insieme a Coordinator per estrarre la navigazione.

MVVM sposta la logica di business dal controller a una ViewModel. Il Controller lega solo la ViewModel alla View tramite Combine o un delegato. Coordinator estrae la logica di navigazione — creazione e transizione tra i controller — in una classe separata. Questo approccio è stato adottato nelle migliori pratiche Apple dal 2024.

swift
// Coordinator — gestione della navigazione
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 vs SwiftUI: quando scegliere cosa

La scelta tra UIViewController e SwiftUI View dipende dall'anno di inizio del progetto, dai requisiti di personalizzazione e dalla versione minima supportata di iOS. UIKit con UIViewController rimane la base per i progetti iniziati prima del 2020 e per le applicazioni con una profonda personalizzazione dell'interfaccia.

SwiftUI è adatto per nuovi progetti con iOS 17+, interfacce standard e prototipi. Tuttavia, transizioni personalizzate, lavoro con la fotocamera, MapKit, animazioni complesse di CALayer richiedono UIViewController. Apple raccomanda di combinare gli approcci tramite UIHostingController (SwiftUI dentro UIKit) e UIViewRepresentable (UIKit dentro SwiftUI).

ScenarioUIKit (UIViewController)SwiftUI (View)
Animazione personalizzataControllo totale tramite UIViewPropertyAnimatorLimitato tramite Animation
Lavoro con fotocameraAVCaptureSession + UIViewPreviewTramite UIViewControllerRepresentable
CollectionViewUICollectionView + UICollectionViewLayoutLazyVGrid/LazyHGrid
Adattamento iPadUISplitViewController + UITraitCollectionNavigationSplitView + sizeClass
Velocità di sviluppoPiù lento (layout manuale)Più veloce (dichiarativo)

Domande Frequenti

In cosa differisce UIViewController da UIView?

UIViewController è un controller che gestisce lo schermo e il suo ciclo di vita. UIView è una vista che visualizza il contenuto. Un ViewController contiene una gerarchia di UIView ma non è di per sé un elemento visivo. Un controller gestisce più viste.

Cos'è un Massive View Controller?

Massive View Controller è un anti-pattern in cui UIViewController contiene troppa logica: dati, navigazione, richieste di rete, animazioni. La soluzione è estrarre il codice in servizi separati, coordinatori e ViewModel (MVVM).

Come passare dati tra ViewControllers?

Quattro modi: tramite una proprietà in prepare(for:sender:) (Segue), tramite un delegato (Delegate), tramite una chiusura (Closure), tramite un servizio condiviso. Per un accoppiamento debole, usa Coordinator + Delegate o Combine.

Cos'è un Container View Controller?

Container View Controller è un controller che gestisce ViewController figli. Esempi: UINavigationController, UITabBarController, UISplitViewController. Il controller padre aggiunge figli tramite addChild, passa da uno all'altro e gestisce il loro layout.

Quando usare UIViewController invece di SwiftUI View?

UIViewController — per animazioni personalizzate complesse, lavoro con fotocamera, mappe, video, UICollectionView con layout personalizzato. SwiftUI View — per interfacce standard su iOS 13+. La combinazione tramite UIHostingController è accettabile.

Riepilogo

  • UIViewController — la classe UIKit centrale per gestire lo schermo, la gerarchia UIView e il ciclo di vita
  • Lifecycle consiste di cinque metodi: viewDidLoad, viewWillAppear, viewDidAppear, viewWillDisappear, viewDidDisappear
  • viewDidLoad — il punto di configurazione iniziale dell'UI, chiamato una volta durante la vita del controller
  • viewWillAppear — chiamato ogni volta prima della visualizzazione, adatto per aggiornare i dati e configurare la barra di navigazione
  • Container View Controller (UINavigationController, UITabBarController) gestisce la gerarchia dei controller figli
  • Massive View Controller è risolto tramite MVVM (estrazione della logica in ViewModel) e Coordinator (estrazione della navigazione)
  • UIViewController e SwiftUI possono essere combinati tramite UIHostingController e UIViewRepresentable per applicazioni ibride

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche