viewDidLoad — je první metoda, kterou UIKit zavolá po načtení View UIViewController do paměti. Podle Apple Developer Documentation se tato metoda volá přesně jednou za celou dobu existence controlleru. viewDidLoad je hlavní místo pro počáteční nastavení rozhraní, registraci buněk a inicializaci dat.
Hlavní body
viewDidLoad — je instanční metoda UIViewController, kterou UIKit zavolá ihned po načtení View controlleru do paměti RAM. V tomto okamžiku jsou všechny vlastnosti IBOutlet již propojeny s prvky rozhraní, ale View ještě nebyla přidána do hierarchie oken a není pro uživatele viditelná. Vývojář tuto metodu přepisuje, aby provedl počáteční konfiguraci obrazovky.
Metoda je součástí ViewController Lifecycle a následuje bezprostředně po loadView, pokud je View vytvářena programově, nebo po načtení z Storyboard. V typickém projektu je viewDidLoad nejčastěji přepisovanou metodou UIViewController, protože poskytuje bezpečný bod pro práci s subviews, které již existují a jsou připraveny ke konfiguraci.
Důležitý detail: v okamžiku volání viewDidLoad rozměry View ještě neodpovídají konečným — Auto Layout nedokončil průchody a frame se může lišit od očekávaného. Pro výpočty závislé na rozměrech se používá viewDidLayoutSubviews.
Načasování volání viewDidLoad závisí na tom, jak je controller inicializován. Ve většině případů UIKit volá tuto metodu automaticky při prvním přístupu k vlastnosti view controlleru — nazývá se to mechanismus lazy-loading UIViewController.
Když NavigationController nebo TabBarController poprvé zobrazí vaši obrazovku, UIKit zkontroluje, zda je View načtena. Pokud ne — zavolá se loadView (nebo načtení ze Storyboard), po čemž okamžitě následuje viewDidLoad. Toto je standardní scénář a nastává jednou pro každou instanci controlleru.
override func viewDidLoad() {
super.viewDidLoad()
print("View načtena — lze nastavit rozhraní")
setupUI()
configureTableView()
}
viewDidLoad se nevolá znovu při návratu na obrazovku pomocí back button nebo dismiss. Pokud vaše logika závisí na tom, že se obrazovka znovu objeví — umístěte ji do viewWillAppear. Toto je jedna z nejčastějších koncepčních chyb: vývojáři očekávají, že viewDidLoad se spustí při každém zobrazení, ale UIKit jej volá pouze jednou.
Někdy vývojáři vynucují volání view controlleru, aby spustili načítání předem: let _ = controller.view. Toto vynutí volání loadView a viewDidLoad před tím, než se controller objeví na obrazovce. Tento trik se používá, když je třeba připravit View předem pro plynulý přechod.
viewDidLoad je určen pro jednorázové konfigurační operace, které nezávisí na tom, zda je obrazovka viditelná. Správné použití této metody je klíčem k čisté architektuře a předvídatelnému chování controlleru.
V viewDidLoad se registrují nib soubory a třídy pro UITableView a UICollectionView, nastavují se delegáti a určují se počáteční hodnoty vlastností UI prvků. Protože všechna IBOutlet jsou v tomto okamžiku již propojena, lze bezpečně přistupovat k label.text, imageView.image a dalším vlastnostem subviews.
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.register(
CustomCell.self,
forCellReuseIdentifier: CustomCell.identifier
)
title = "Hlavní obrazovka"
}
Zde se vytváří viewModel, inicializuje se data source pomocí polí a přihlašuje se k oznámením, která mají fungovat po celou dobu života controlleru. Například přihlášení k UIApplication.willEnterForegroundNotification pro aktualizaci dat při návratu z pozadí — vhodný kandidát pro viewDidLoad. ViewModel v moderní iOS architektuře slouží jako spojovací článek mezi controllerem a obchodní logikou a jeho inicializace právě v viewDidLoad zajišťuje připravenost dat v okamžiku prvního zobrazení obrazovky.
Věnujte zvláštní pozornost nastavení data source pro tabulky a kolekce. Pokud vaše tabulka používá UIFetchedResultsController nebo NSFetchedResultsController s Core Data, inicializujte fetch request a delegáta v viewDidLoad. To zaručuje, že při prvním zobrazení obrazovky bude tabulka již naplněna daty bez dodatečných dotazů.
V viewDidLoad se konfigurují tlačítka NavigationBar, nastavuje se large title, přidává se search controller a nastavují se tlačítka edit/done. Tyto prvky se při opakovaném zobrazení obrazovky mění zřídka, takže jejich inicializace zde je optimální.
Ne všechny operace jsou vhodné pro viewDidLoad. Některé akce umístěné v této metodě vedou k nadměrné spotřebě paměti, nesprávnému chování nebo chybám při opakovaném zobrazení obrazovky.
Vyhněte se spouštění síťových požadavků, jejichž výsledek ovlivňuje pouze UI. Pokud požadavek skončí před zobrazením obrazovky, uživatel neuvidí výsledek, a pokud po — data mohou být zastaralá. Spusťte načítání v viewDidLoad, ale aktualizujte UI v viewWillAppear.
Neprovádějte v viewDidLoad operace závislé na rozměrech a poloze View. V okamžiku volání Auto Layout nedokončil průchody a frame nemusí být konečný. Pro výpočty používejte viewDidLayoutSubviews nebo přepište updateViewConstraints.
Nepřihlašujte se k oznámením, která fungují pouze když je obrazovka viditelná. Oznámení o klávesnici, oznámení o změně obsahu podřízených controllerů — přihlaste se k nim v viewWillAppear a odhlaste se v viewDidDisappear, abyste předešli zbytečným voláním a únikům paměti.
Nevolejte metody vyžadující viditelnou obrazovku. Například pokus o zobrazení UIAlertController z viewDidLoad způsobí chybu, protože View controlleru ještě nebyla přidána do hierarchie oken. Všechny operace UI závislé na window nebo presentedViewController by měly být prováděny až po zobrazení obrazovky.
Neinicializujte těžké zdroje bez potřeby. Pokud se obrazovka otevírá zřídka nebo data nejsou zobrazena okamžitě, odložte vytváření náročných objektů na dobu, kdy jsou skutečně potřeba. Líná inicializace vlastností ve Swift je vestavěný mechanismus pro řešení tohoto úkolu: vlastnost s modifikátorem lazy bude vytvořena až při prvním přístupu, což šetří paměť a zrychluje načítání obrazovky.
Nepoužívejte viewDidLoad pro operace, které by měly být prováděny při každém zobrazení obrazovky. Toto je nejzákladnější chyba: začínající vývojáři často umísťují logiku aktualizace dat do viewDidLoad a diví se, že při návratu z jiné obrazovky se tabulka znovu nenačte. Pokud se operace má opakovat při každém zobrazení — použijte viewWillAppear. Pokud se má provést jednou za život — viewDidLoad. Pamatujte si toto jednoduché pravidlo, abyste předešli většině problémů s životním cyklem UIViewController.
Podívejme se na tři praktické příklady, které demonstrují správné použití viewDidLoad v reálných projektech. Každý příklad řeší konkrétní úkol konfigurace obrazovky.
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(
PhotoCell.self,
forCellWithReuseIdentifier: PhotoCell.reuseId
)
collectionView.register(
HeaderView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: HeaderView.reuseId
)
viewModel.delegate = self
viewModel.fetchInitialPage()
}
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel()
label.text = "Ahoj, světe!"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
V viewDidLoad se také nastavují prvky zobrazované při absenci dat: prázdný stav, loader, placeholder. Tyto komponenty se vytvářejí jednou a znovu používají při každém zobrazení obrazovky. Skrytí nebo zobrazení těchto prvků je řízeno v viewWillAppear v závislosti na aktuálních datech.
override func viewDidLoad() {
super.viewDidLoad()
emptyStateLabel = UILabel()
emptyStateLabel.text = "Žádná data"
emptyStateLabel.textAlignment = .center
emptyStateLabel.isHidden = true
view.addSubview(emptyStateLabel)
activityIndicator = UIActivityIndicatorView(style: .medium)
activityIndicator.hidesWhenStopped = true
view.addSubview(activityIndicator)
}
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(handleEnterForeground),
name: UIApplication.willEnterForegroundNotification,
object: nil
)
}
@objc private func handleEnterForeground() {
refreshContent()
}
Často kladené otázky
Za normálních podmínek ne — UIKit volá viewDidLoad jednou po načtení View do paměti. Pokud je controller zničen a znovu vytvořen, viewDidLoad se spustí pro novou instanci.
Ano, rozhodně. Volání super.viewDidLoad zaručuje, že UIKit provede vnitřní nastavení nezbytné pro správnou funkci Lifecycle. Vždy volejte super jako první věc v metodě.
viewDidLoad se volá jednou při načtení View. viewWillAppear se volá pokaždé před zobrazením obrazovky. První — pro jednorázové nastavení, druhý — pro aktualizaci dat a stavu.
Těžké synchronní operace v viewDidLoad blokují main thread a zpožďují zobrazení obrazovky. Asynchronní načítání jsou povolena, ale při aktualizaci UI po jejich dokončení je třeba mít na paměti, že obrazovka může být již skryta.
Přímo viewDidLoad nelze volat — volá ho UIKit. Pro vynucení načtení View přistupte k vlastnosti controller.view. Tím se automaticky spustí loadView a viewDidLoad.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také