viewDidLoad — är den första metoden som UIKit anropar efter att View för UIViewController har laddats in i minnet. Enligt Apple Developer Documentation anropas denna metod exakt en gång under hela kontrollerns livstid. viewDidLoad är den huvudsakliga platsen för initial konfiguration av gränssnittet, registrering av celler och initiering av data.
Huvudpunkter
viewDidLoad — är en instansmetod för UIViewController som UIKit anropar omedelbart efter att kontrollerns View har laddats in i RAM-minnet. I detta ögonblick är alla IBOutlet-egenskaper redan anslutna till gränssnittselementen, men View har ännu inte lagts till i fönsterhierarkin och är inte synlig för användaren. Utvecklaren åsidosätter denna metod för att utföra den initiala konfigurationen av skärmen.
Metoden är en del av ViewController Lifecycle och kommer omedelbart efter loadView, om View skapas programmatiskt, eller efter inladdning från Storyboard. I ett typiskt projekt är viewDidLoad den mest åsidosatta metoden för UIViewController, eftersom den ger en säker punkt för att arbeta med subviews som redan finns och är redo för konfiguration.
En viktig detalj: vid tidpunkten för anropet av viewDidLoad överensstämmer View:s dimensioner ännu inte med de slutgiltiga — Auto Layout har inte slutfört passen och ramen kan skilja sig från förväntad. För beräkningar som beror på dimensioner används viewDidLayoutSubviews.
Tidpunkten för anropet av viewDidLoad beror på hur kontrollern initieras. I de flesta fall anropar UIKit denna metod automatiskt vid första åtkomsten till kontrollerns view-egenskap — detta kallas UIViewController:s lazy-loading-mekanism.
När NavigationController eller TabBarController för första gången visar din skärm, kontrollerar UIKit om View är laddad. Om inte — anropas loadView (eller inladdning från Storyboard), varefter viewDidLoad omedelbart aktiveras. Detta är standardscenariot och inträffar en gång för varje instans av kontrollern.
override func viewDidLoad() {
super.viewDidLoad()
print("View laddad — gränssnittet kan konfigureras")
setupUI()
configureTableView()
}
viewDidLoad anropas inte igen vid återgång till skärmen via back button eller dismiss. Om din logik beror på att skärmen visas igen — placera den i viewWillAppear. Detta är ett av de vanligaste konceptuella felen: utvecklare förväntar sig att viewDidLoad aktiveras vid varje visning, men UIKit anropar det bara en gång.
Ibland tvingar utvecklare fram anrop av kontrollerns view för att starta inladdning i förväg: let _ = controller.view. Detta tvingar fram anrop av loadView och viewDidLoad innan kontrollern visas på skärmen. Detta trick används när View behöver förberedas i förväg för en smidig övergång.
viewDidLoad är avsett för engångskonfigurationsoperationer som inte beror på om skärmen är synlig. Korrekt användning av denna metod är nyckeln till en ren arkitektur och förutsägbart beteende hos kontrollern.
I viewDidLoad registreras nib-filer och klasser för UITableView och UICollectionView, delegater konfigureras och initiala värden för UI-elementens egenskaper anges. Eftersom alla IBOutlet är redan anslutna vid denna tidpunkt, kan man säkert komma åt label.text, imageView.image och andra egenskaper hos subviews.
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.register(
CustomCell.self,
forCellReuseIdentifier: CustomCell.identifier
)
title = "Huvudskärm"
}
Här skapas viewModel, data source initieras med arrayer och man prenumererar på notifieringar som ska fungera under kontrollerns hela livstid. Till exempel, prenumeration på UIApplication.willEnterForegroundNotification för att uppdatera data vid återgång från bakgrunden — en lämplig kandidat för viewDidLoad. ViewModel i modern iOS-arkitektur fungerar som en länk mellan kontrollern och affärslogiken, och dess initiering just i viewDidLoad säkerställer att data är redo vid det första visningstillfället av skärmen.
Ägna särskild uppmärksamhet åt konfigurationen av data source för tabeller och samlingar. Om din tabell använder UIFetchedResultsController eller NSFetchedResultsController med Core Data, initiera fetch request och delegat i viewDidLoad. Detta garanterar att tabellen vid första visningen av skärmen redan är fylld med data utan ytterligare frågor.
I viewDidLoad konfigureras NavigationBar-knappar, large title ställs in, search controller läggs till och edit/done-knappar ställs in. Dessa element ändras sällan vid upprepade visningar av skärmen, så deras initiering här är optimal.
Inte alla operationer är lämpliga i viewDidLoad. Vissa åtgärder som placeras i denna metod leder till överdriven minnesförbrukning, felaktigt beteende eller buggar vid upprepad visning av skärmen.
Undvik att starta nätverksförfrågningar vars resultat endast påverkar UI. Om förfrågan slutförs innan skärmen visas, kommer användaren inte att se resultatet, och om efter — kan data vara föråldrad. Starta inladdning i viewDidLoad, men uppdatera UI i viewWillAppear.
Utför inte i viewDidLoad operationer som beror på View:s dimensioner och position. Vid anropstillfället har Auto Layout inte slutfört passen och ramen kan vara icke-slutgiltig. För beräkningar, använd viewDidLayoutSubviews eller åsidosätt updateViewConstraints.
Prenumerera inte på notifieringar som bara är aktiva när skärmen är synlig. Tangentbordsnotifieringar, notifieringar om innehållsändringar i barnkontroller — prenumerera på dem i viewWillAppear och avsluta prenumerationen i viewDidDisappear för att undvika onödiga anrop och minnesläckor.
Anropa inte metoder som kräver en synlig skärm. Till exempel, ett försök att visa UIAlertController från viewDidLoad kommer att orsaka ett fel eftersom kontrollerns View ännu inte har lagts till i fönsterhierarkin. Alla UI-operationer som beror på window eller presentedViewController bör endast utföras efter att skärmen visas.
Initiera inte tunga resurser i onödan. Om skärmen sällan öppnas eller data inte visas omedelbart, skjut upp skapandet av resurskrävande objekt tills de verkligen behövs. Lazy-initiering av egenskaper i Swift är en inbyggd mekanism för att lösa denna uppgift: en egenskap med lazy-modifieraren skapas först vid första åtkomsten, vilket sparar minne och snabbar upp inladdningen av skärmen.
Använd inte viewDidLoad för operationer som ska utföras varje gång skärmen visas. Detta är det mest grundläggande felet: nybörjarutvecklare placerar ofta uppdateringslogik i viewDidLoad och undrar varför tabellen inte laddas om när de återvänder från en annan skärm. Om operationen ska upprepas vid varje visning — använd viewWillAppear. Om den ska utföras en gång under livstiden — viewDidLoad. Kom ihåg denna enkla regel för att undvika de flesta problem med UIViewController:s livscykel.
Låt oss titta på tre praktiska exempel som demonstrerar korrekt användning av viewDidLoad i verkliga projekt. Varje exempel löser en specifik uppgift för skärmkonfiguration.
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 = "Hej, världen!"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
I viewDidLoad konfigureras även element som visas när data saknas: tomt tillstånd, loader, placeholder. Dessa komponenter skapas en gång och återanvänds vid varje visning av skärmen. Döljande eller visning av dessa element styrs i viewWillAppear beroende på aktuell data.
override func viewDidLoad() {
super.viewDidLoad()
emptyStateLabel = UILabel()
emptyStateLabel.text = "Inga 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()
}
Vanliga frågor
Under normala förhållanden nej — UIKit anropar viewDidLoad en gång efter att View har laddats in i minnet. Om kontrollern förstörs och skapas på nytt, kommer viewDidLoad att fungera för den nya instansen.
Ja, absolut. Anropet av super.viewDidLoad garanterar att UIKit utför den interna konfiguration som krävs för korrekt funktion av Lifecycle. Anropa alltid super som första sak i metoden.
viewDidLoad anropas en gång vid inladdning av View. viewWillAppear anropas varje gång innan skärmen visas. Den första — för engångskonfiguration, den andra — för uppdatering av data och status.
Tunga synkrona operationer i viewDidLoad blockerar main thread och försenar skärmens visning. Asynkrona inladdningar är tillåtna, men vid uppdatering av UI efter slutförande måste man ta hänsyn till att skärmen kan vara redan dold.
Direkt kan viewDidLoad inte anropas — det anropas av UIKit. För att tvinga fram inladdning av View, gå till egenskapen controller.view. Detta kommer automatiskt att utlösa loadView och viewDidLoad.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också