viewDidLoad — to pierwsza metoda, którą UIKit wywołuje po załadowaniu View UIViewController do pamięci. Według Apple Developer Documentation, ta metoda jest wywoływana dokładnie raz przez cały czas istnienia kontrolera. viewDidLoad to główne miejsce do wstępnej konfiguracji interfejsu, rejestracji komórek i inicjalizacji danych.
Najważniejsze
viewDidLoad to metoda instancji UIViewController, którą UIKit wywołuje natychmiast po załadowaniu View kontrolera do pamięci RAM. W tym momencie wszystkie właściwości IBOutlet są już połączone z elementami interfejsu, ale View nie została jeszcze dodana do hierarchii okien i nie jest widoczna dla użytkownika. Deweloper nadpisuje tę metodę, aby wykonać wstępną konfigurację ekranu.
Metoda jest częścią ViewController Lifecycle i następuje bezpośrednio po loadView, jeśli View jest tworzona programowo, lub po załadowaniu z Storyboard. W typowym projekcie viewDidLoad jest najczęściej nadpisywaną metodą UIViewController, ponieważ zapewnia bezpieczny punkt do pracy z subviews, które już istnieją i są gotowe do konfiguracji.
Ważny szczegół: w momencie wywołania viewDidLoad rozmiary View nie odpowiadają jeszcze finalnym — Auto Layout nie zakończył przebiegów, a frame może różnić się od oczekiwanego. Do obliczeń zależnych od rozmiarów używa się viewDidLayoutSubviews.
Czas wywołania viewDidLoad zależy od tego, jak inicjalizowany jest kontroler. W większości przypadków UIKit wywołuje tę metodę automatycznie przy pierwszym odwołaniu do właściwości view kontrolera — nazywa się to mechanizmem lazy-loading UIViewController.
Kiedy NavigationController lub TabBarController po raz pierwszy pokazuje twój ekran, UIKit sprawdza, czy View jest załadowana. Jeśli nie — wywoływane jest loadView (lub ładowanie z Storyboard), po czym natychmiast uruchamia się viewDidLoad. To standardowy scenariusz i występuje jednokrotnie dla każdej instancji kontrolera.
override func viewDidLoad() {
super.viewDidLoad()
print("View załadowana — można konfigurować interfejs")
setupUI()
configureTableView()
}
viewDidLoad nie jest wywoływany ponownie przy powrocie do ekranu przez back button lub dismiss. Jeśli twoja logika zależy od tego, że ekran pojawia się ponownie — umieść ją w viewWillAppear. To jeden z najczęstszych błędów koncepcyjnych: deweloperzy oczekują, że viewDidLoad zadziała przy każdym wyświetleniu, ale UIKit wywołuje go tylko raz.
Czasami deweloperzy wymuszają wywołanie view u kontrolera, aby zainicjować ładowanie z wyprzedzeniem: let _ = controller.view. To wymusza wywołanie loadView i viewDidLoad przed pojawieniem się kontrolera na ekranie. Taki trik stosuje się, gdy trzeba przygotować View z wyprzedzeniem dla płynnego przejścia.
viewDidLoad jest przeznaczony do jednorazowych operacji konfiguracyjnych, które nie zależą od tego, czy ekran jest widoczny. Prawidłowe użycie tej metody to klucz do czystej architektury i przewidywalnego zachowania kontrolera.
W viewDidLoad rejestruje się pliki nib i klasy dla UITableView i UICollectionView, konfiguruje delegatów, ustawia początkowe wartości właściwości elementów UI. Ponieważ wszystkie IBOutlet są w tym momencie już połączone, można bezpiecznie odwoływać się do label.text, imageView.image i innych właściwości subviews.
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.register(
CustomCell.self,
forCellReuseIdentifier: CustomCell.identifier
)
title = "Ekran główny"
}
Tutaj tworzy się viewModel, inicjalizuje data source tablicami, subskrybuje powiadomienia, które mają działać przez cały czas życia kontrolera. Na przykład subskrypcja UIApplication.willEnterForegroundNotification do aktualizacji danych przy powrocie z tła — to odpowiedni kandydat do viewDidLoad. ViewModel w nowoczesnej architekturze iOS pełni rolę łącznika między kontrolerem a logiką biznesową, a jego inicjalizacja właśnie w viewDidLoad zapewnia gotowość danych w momencie pierwszego pojawienia się ekranu.
Szczególną uwagę należy zwrócić na konfigurację data source dla tabel i kolekcji. Jeśli twoja tabela używa UIFetchedResultsController lub NSFetchedResultsController z Core Data, zainicjuj fetch request i delegata w viewDidLoad. To gwarantuje, że przy pierwszym pojawieniu się ekranu tabela będzie już wypełniona danymi bez dodatkowych zapytań.
W viewDidLoad konfiguruje się przyciski NavigationBar, ustawia large title, dodaje search controller i ustawia przyciski edit/done. Te elementy rzadko zmieniają się przy ponownym wyświetlaniu ekranu, więc ich inicjalizacja tutaj jest optymalna.
Nie wszystkie operacje są odpowiednie w viewDidLoad. Niektóre działania umieszczone w tej metodzie prowadzą do nadmiernego zużycia pamięci, nieprawidłowego zachowania lub błędów przy ponownym wyświetlaniu ekranu.
Unikaj uruchamiania zapytań sieciowych, których wynik wpływa tylko na UI. Jeśli zapytanie zakończy się przed pojawieniem się ekranu, użytkownik nie zobaczy wyniku, a jeśli po — dane mogą być nieaktualne. Inicjuj ładowanie w viewDidLoad, ale aktualizuj UI w viewWillAppear.
Nie wykonuj w viewDidLoad operacji zależnych od rozmiarów i położenia View. W momencie wywołania Auto Layout nie zakończył przebiegów, a frame może być nieostateczny. Do obliczeń używaj viewDidLayoutSubviews lub nadpisz updateViewConstraints.
Nie subskrybuj powiadomień, które działają tylko gdy ekran jest widoczny. Powiadomienia klawiatury, powiadomienia o zmianie zawartości kontrolerów potomnych — subskrybuj je w viewWillAppear i anuluj subskrypcję w viewDidDisappear, aby uniknąć niepotrzebnych wywołań i wycieków.
Nie wywołuj metod wymagających widocznego ekranu. Na przykład próba pokazania UIAlertController z viewDidLoad spowoduje błąd, ponieważ View kontrolera nie została jeszcze dodana do hierarchii okien. Wszelkie operacje UI zależne od window lub presentedViewController muszą być wykonywane dopiero po pojawieniu się ekranu.
Nie inicjalizuj ciężkich zasobów bez potrzeby. Jeśli ekran jest otwierany rzadko lub dane nie są wyświetlane od razu, odłóż tworzenie zasobożernych obiektów do momentu, gdy będą rzeczywiście potrzebne. Lazy-inicjalizacja właściwości w Swift to wbudowany mechanizm do rozwiązania tego zadania: właściwość z modyfikatorem lazy zostanie utworzona dopiero przy pierwszym odwołaniu, co oszczędza pamięć i przyspiesza ładowanie ekranu.
Nie używaj viewDidLoad do operacji, które mają być wykonywane przy każdym pojawieniu się ekranu. To najbardziej fundamentalny błąd: początkujący deweloperzy często umieszczają logikę aktualizacji danych w viewDidLoad i dziwią się, że przy powrocie z innego ekranu tabela nie przeładowuje się. Jeśli operacja ma się powtarzać przy każdym wyświetleniu — użyj viewWillAppear. Jeśli ma się wykonać raz w ciągu życia — viewDidLoad. Zapamiętaj tę prostą zasadę, aby uniknąć większości problemów z cyklem życia UIViewController.
Omówimy trzy praktyczne przykłady demonstrujące prawidłowe użycie viewDidLoad w rzeczywistych projektach. Każdy przykład rozwiązuje konkretne zadanie konfiguracji ekranu.
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 = "Witaj, świecie!"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
}
W viewDidLoad konfiguruje się również elementy wyświetlane przy braku danych: stan pusty, loader, placeholder. Te komponenty są tworzone raz i ponownie wykorzystywane przy każdym pojawieniu się ekranu. Ukrywanie lub pokazywanie tych elementów jest kontrolowane w viewWillAppear w zależności od aktualnych danych.
override func viewDidLoad() {
super.viewDidLoad()
emptyStateLabel = UILabel()
emptyStateLabel.text = "Brak danych"
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()
}
Często zadawane pytania
W normalnych warunkach nie — UIKit wywołuje viewDidLoad raz po załadowaniu View do pamięci. Jeśli kontroler jest niszczony i tworzony od nowa, viewDidLoad zadziała dla nowej instancji.
Tak, koniecznie. Wywołanie super.viewDidLoad gwarantuje, że UIKit wykona wewnętrzną konfigurację niezbędną do prawidłowego działania Lifecycle. Zawsze wywołuj super jako pierwszą rzecz w metodzie.
viewDidLoad jest wywoływany raz przy ładowaniu View. viewWillAppear jest wywoływany za każdym razem przed pojawieniem się ekranu. Pierwszy — do jednorazowej konfiguracji, drugi — do aktualizacji danych i stanu.
Ciężkie synchroniczne operacje w viewDidLoad blokują main thread i opóźniają pojawienie się ekranu. Asynchroniczne ładowania są dopuszczalne, ale aktualizacja UI po ich zakończeniu musi uwzględniać, że ekran może być już ukryty.
Bezpośrednio nie można wywołać viewDidLoad — wywołuje go UIKit. Aby wymusić załadowanie View, odwołaj się do właściwości controller.view. To uruchomi loadView i viewDidLoad automatycznie.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również