Chcemy zrozumieć cykl życia iOS UIViewController

299

Czy możesz wyjaśnić mi prawidłowy sposób zarządzania UIViewControllercyklem życia?

W szczególności chciałbym wiedzieć, jak korzystać Initialize, ViewDidLoad, ViewWillAppear, ViewDidAppear, ViewWillDisappear, ViewDidDisappear, ViewDidUnloadi Disposemetody Mono Dotyk dla UIViewControllerklasy.

Lorenzo B.
źródło
Czy są jakieś informacje lub łącze do OSX ViewController i WindowController? Udostępnij to.
Anoop Vaidya

Odpowiedzi:

410

Wszystkie te polecenia są wywoływane automatycznie przez iOS w odpowiednim czasie, gdy ładujesz / prezentujesz / ukrywasz kontroler widoku. Ważne jest, aby pamiętać, że metody te są przywiązane do samych siebie, UIViewControllera nie do UIViewnich. Nie uzyskasz żadnej z tych funkcji tylko przy użyciu UIView.

Jest świetna dokumentacja na stronie Apple tutaj . Mówiąc prosto:

  • ViewDidLoad- Wywoływany podczas tworzenia klasy i ładowania z Xib. Idealne do początkowej konfiguracji i jednorazowej pracy.

  • ViewWillAppear- Wywoływany tuż przed pojawieniem się widoku, dobry do ukrywania / pokazywania pól lub wszelkich operacji, które chcesz wykonać za każdym razem, zanim widok będzie widoczny. Ponieważ możesz poruszać się między widokami, będzie to wywoływane za każdym razem, gdy twój widok pojawi się na ekranie.

  • ViewDidAppear - Wywoływany po wyświetleniu widoku - świetne miejsce do rozpoczęcia animacji lub ładowania danych zewnętrznych z interfejsu API.

  • ViewWillDisappear/ DidDisappear- Taki sam pomysł jak ViewWillAppear/ ViewDidAppear.

  • ViewDidUnload/ ViewDidDispose- W Objective-C, tutaj robisz porządki i wypuszczasz rzeczy, ale jest to obsługiwane automatycznie, więc nie musisz nic więcej robić.

Jacob Knobel
źródło
86
Ten tekst jest nieco mylący, ponieważ ViewDidLoad nie powinien być używany do pracy jednorazowej. Można go wywołać kilka razy, jeśli widok zostanie zwolniony z powodu małej ilości pamięci, a następnie ponownie załadowany.
Ricky Helgesson,
4
ViewDidLoad nie jest wywoływany podczas tworzenia / inicjowania kontrolera widoku. Nazywa się to przy pierwszym wykonaniu dowolnego widoku związanego z widokiem kontrolera widoku. Jak dodać go jako widok podrzędny, ustawić ramkę itp. Jest również wywoływany oczywiście podczas ładowania ze stalówki.
Jason Grandelli
3
ViewDidAppear - Wywoływany po wyświetleniu widoku - świetne miejsce do rozpoczęcia animacji lub ładowania danych zewnętrznych z interfejsu API. Dlaczego warto rozpocząć ładowanie danych? Dlaczego nie viewDidLoad?
Anton Chikin
1
co z metodą loadView, jeśli jest wywoływana po raz pierwszy, gdy stalówka załadowana do pamięci przed viewDidLoad, czy nie.
iHulk,
@chakrit jest to dobry punkt - viewDidAppear to świetne miejsce do odświeżania danych (w razie potrzeby). Nie zgadzam się z KVO, ponieważ może to powodować niepożądane odświeżenia widoków, które nigdy nie są oglądane przez użytkownika.
Anton Chikin,
409

AKTUALIZACJA: ViewDidUnload został przestarzały w iOS 6, więc odpowiednio zaktualizowałem odpowiedź.

Cykl życia UIViewController przedstawiono tutaj:

Schemat cyklu życia kontrolera widoku

Zaletą korzystania z Xamarin Native / Mono Touch jest to, że korzysta z natywnych interfejsów API, a zatem przebiega w tym samym cyklu życia ViewController, jak w dokumentacji Apple.

Haider
źródło
17
Dokąd idą viewWillLayoutSubviews i viewDidLayoutSubviews na tym schemacie blokowym?
Max_Power89
7
Ten schemat jest niedokładny. viewDidUnload jest przestarzałe od iOS6: stackoverflow.com/questions/12509102/…
okul
2
To po prostu źle . Kolejny przykład po prostu złej odpowiedzi na SO, z biegiem lat. Obliczenia są wysoce niestatyczne.
Fattie,
186

Dotyczy to najnowszych wersji iOS (zmodyfikowanych za pomocą Xcode 9.3, Swift 4.1 ). Poniżej znajdują się wszystkie etapy, które składają się na UIViewControllerpełny cykl życia .

  • loadView()

  • loadViewIfNeeded()

  • viewDidLoad()

  • viewWillAppear(_ animated: Bool)

  • viewWillLayoutSubviews()

  • viewDidLayoutSubviews()

  • viewDidAppear(_ animated: Bool)

  • viewWillDisappear(_ animated: Bool)

  • viewDidDisappear(_ animated: Bool)

Pozwól mi wyjaśnić wszystkie te etapy.

1. loadView

To zdarzenie tworzy / ładuje widok zarządzany przez kontroler. Może zostać załadowany ze skojarzonego pliku stalówki lub pusty, UIViewjeśli znaleziono wartość NULL. To sprawia, że ​​jest to dobre miejsce do programowego tworzenia widoków w kodzie.

W tym miejscu podklasy powinny tworzyć własną hierarchię widoków, jeśli nie używają stalówki. Nigdy nie należy dzwonić bezpośrednio. Zastępuj tę metodę tylko wtedy, gdy programowo tworzysz widoki i przypisujesz widok główny do viewwłaściwości Nie wywoływaj super metody, gdy przesłonisz loadView

2) loadViewIfNeeded

Jeśli viewControllernie ustawiono jeszcze widoku prądu, ta metoda załaduje widok, ale pamiętaj, że jest to dostępne tylko w iOS> = 9.0. Więc jeśli wspierasz iOS <9.0, nie oczekuj, że pojawi się na zdjęciu.

Ładuje widok kontrolera widoku, jeśli nie został jeszcze ustawiony.

3) viewDidLoad

viewDidLoadZdarzenie jest wywoływane tylko wtedy, gdy widok jest tworzony i ładowane do pamięci, ale granice dla widoku nie są jeszcze zdefiniowane. Jest to dobre miejsce do inicjalizacji obiektów, które będą używane przez kontroler widoku.

Wywoływany po załadowaniu widoku. W przypadku kontrolerów widoku utworzonych w kodzie jest to po -loadView. W przypadku kontrolerów widoku niezarchiwizowanych z końcówki następuje to po ustawieniu widoku.

4 viewWillAppear

To zdarzenie powiadamia o viewControllerkażdym wyświetleniu widoku na ekranie. W tym kroku widok ma zdefiniowane granice, ale orientacja nie jest ustawiona.

Wywoływany, gdy widok ma być widoczny. Domyślnie nic nie robi.

5 viewWillLayoutSubviews

To pierwszy krok w cyklu życia, w którym granice są finalizowane. Jeśli nie używasz ograniczeń ani automatycznego układu, prawdopodobnie chcesz tutaj zaktualizować widoki podrzędne. Jest to dostępne tylko w iOS> = 5.0. Więc jeśli wspierasz iOS <5.0, nie oczekuj, że pojawi się na zdjęciu.

Wywoływany tuż przed wywołaniem układu widoku kontrolera widoku Metoda Subviews jest wywoływana. Podklasy można wdrażać w razie potrzeby. Domyślnie jest to nop.

6. viewDidLayoutSubviews

To zdarzenie powiadamia kontroler widoku, że podviewy zostały skonfigurowane. Jest to dobre miejsce do wprowadzania zmian w widokach podrzędnych po ich ustawieniu. Jest to dostępne tylko w iOS> = 5.0. Więc jeśli wspierasz iOS <5.0, nie oczekuj, że pojawi się na zdjęciu.

Wywoływany zaraz po wywołaniu układu widoku kontrolera widoku Metoda Subviews jest wywoływana. Podklasy można wdrażać w razie potrzeby. Domyślnie jest to nop.

7 viewDidAppear

W viewDidAppearZdarzenie po widzenia prezentowany jest na ekranie. Co sprawia, że ​​jest to dobre miejsce na uzyskanie danych z usługi zaplecza lub bazy danych.

Wywoływany, gdy widok został w pełni przeniesiony na ekran. Domyślnie nic nie robi

8 viewWillDisappear

W viewWillDisappearZdarzenie gdy pogląd przedstawiony viewControllerjest o zniknąć oddalenie, pokrywę lub chować się za innych viewController. To dobre miejsce, w którym możesz ograniczyć połączenia sieciowe, unieważnić timer lub zwolnić związane z tym obiektyviewController .

Wywoływany, gdy widok zostanie odrzucony, zakryty lub w inny sposób ukryty.

9 viewDidDisappear

Jest to ostatni etap cyklu życia, którym każdy może się zająć, ponieważ to wydarzenie jest uruchamiane tuż po wyświetleniu widoku viewController zniknięciu, odrzuceniu, zasłonięciu lub ukryciu .

Wywoływany po tym, jak widok został odrzucony, zakryty lub w inny sposób ukryty. Domyślnie nic nie robi

Teraz, tak jak Apple , wdrażając te metody, powinieneś pamiętać o wywołaniu superimplementacji tej konkretnej metody.

Jeśli podklasujesz UIViewController, musisz wywołać super implementację tej metody, nawet jeśli nie używasz NIB. (Dla wygody domyślna metoda init zrobi to za Ciebie i określi zero dla obu argumentów tych metod.) W określonym NIB, proxy właściciela pliku powinno mieć klasę ustawioną na podklasę kontrolera widoku, z ujściem widoku podłączony do głównego widoku. Jeśli wywołasz tę metodę z zerową nazwą końcówki, wówczas -loadViewmetoda tej klasy spróbuje załadować NIB, którego nazwa jest taka sama jak klasa twojego kontrolera widoku. Jeśli tak naprawdę nie ma takiego NIB, musisz albo wywołać -setView:przed -viewwywołaniem go, albo zastąpić -loadViewmetodę programowego konfigurowania twoich widoków.

Mam nadzieję, że to pomogło. Dzięki.

AKTUALIZACJA - Jak wskazał @ThomasW w komentarzu viewWillLayoutSubviewsi viewDidLayoutSubviewsbędzie również wywoływany w innych momentach, gdy ładowane są widoki podrzędne głównego widoku, na przykład, gdy ładowane są komórki widoku tabeli lub widoku kolekcji.

AKTUALIZACJA - Jak wskazał @Maria w komentarzu, loadViewzaktualizowano opis

po zakończeniu
źródło
6
viewWillLayoutSubviewsi viewDidLayoutSubviewsbędzie również wywoływany w innych momentach, gdy załadowane zostaną widoki podrzędne głównego widoku, na przykład, gdy załadowane zostaną komórki widoku tabeli lub widoku kolekcji.
ThomasW,
Odpowiedź jest nieco myląca: loadView () jest zawsze wywoływany, po prostu nie należy go zastępować, gdy widok kontrolera utworzony w IB.
Maria,
@Maria Proszę, edytuj odpowiedź, jeśli uważasz, że można ją poprawić. Dzięki.
onCompletion
Domyślnie nic nie jest złe viewWillAppear viewDidAppear viewDidDisappear. W pewnym momencie musisz zadzwonić super.
Mick
47

iOS 10,11 (Swift 3.1, Swift 4.0)

Zgodnie UIViewControllerz UIKitdeweloperów,

1. loadView ()

W tym miejscu podklasy powinny tworzyć własną hierarchię widoków, jeśli nie używają stalówki . Nigdy nie należy dzwonić bezpośrednio.

2. loadViewIfNeeded ()

Ładuje widok kontrolera widoku, jeśli nie został jeszcze ustawiony.

3. viewDidLoad ()

Wywoływany po załadowaniu widoku. W przypadku kontrolerów widoku utworzonych w kodzie jest to po -loadView. W przypadku kontrolerów widoku niezarchiwizowanych z końcówki następuje to po ustawieniu widoku.

4. viewWillAppear (_ animowane: Bool)

Wywoływany, gdy widok ma być widoczny. Domyślnie nic nie robi

5. viewWillLayoutSubviews ()

Wywoływany tuż przed wywołaniem układu widoku kontrolera widoku Metoda Subviews jest wywoływana. Podklasy można wdrażać w razie potrzeby. Domyślnie nic nie robi.

6. viewDidLayoutSubviews ()

Wywoływany zaraz po wywołaniu układu widoku kontrolera widoku Metoda Subviews jest wywoływana. Podklasy można wdrażać w razie potrzeby. Domyślnie nic nie robi.

7. viewDidAppear (_ animowane: Bool)

Wywoływany, gdy widok został w pełni przeniesiony na ekran. Domyślnie nic nie robi

8. viewWillDisappear (_ animowane: Bool)

Wywoływany, gdy widok zostanie odrzucony, zakryty lub w inny sposób ukryty. Domyślnie nic nie robi

9. viewDidDisappear (_ animowane: Bool )

Wywoływany po tym, jak widok został odrzucony, zakryty lub w inny sposób ukryty. Domyślnie nic nie robi

10. viewWillTransition (na wymiar: CGSize, ze koordynatorem: UIViewControllerTransitionCoordinator)

Wywoływany, gdy widok jest przejściowy.

11. willMove (rodzic toParentViewController: UIViewController?)

12. didMove (toParentViewController rodzic: UIViewController?)

Te dwie metody są publiczne dla podklas kontenerów do wywoływania podczas przechodzenia między kontrolerami potomnymi. Jeśli zostaną zastąpione, przesłonięcia powinny zapewnić wywołanie super.

Argument nadrzędny w obu tych metodach jest zerowy, gdy dziecko jest usuwane z jego rodzica; w przeciwnym razie jest równy nowemu nadrzędnemu kontrolerowi widoku.

13. didReceiveMemoryWarning ()

Wywoływany, gdy aplikacja nadrzędna otrzyma ostrzeżenie o pamięci. W iOS 6.0 domyślnie nie wyczyści widoku.

Rajamohan S.
źródło
2
Naprawdę naprawdę słychać, że przepełnienie stosu nie usunie wszystkich błędnych i niepełnych odpowiedzi z tego całego wątku. Twoja odpowiedź wydaje się kompletna, jeśli chodzi o wywołania metod, więc zakładam, że twoje są poprawne i pracuję z tym.
Logicsaurus Rex
Co to jest nibwspomniane poniżej loadView?
Petrus Theron
2
@LogicsaurusRex Zgadzam się. W ten sam sposób, w jaki SO oznacza pytania jako duplikaty lub chronione, myślę, że powinno być w stanie oznaczyć odpowiedzi jako przestarzałe lub nieaktualne
rmp251,
Punkt 5 powyżej jest błędny. viewWillLayoutSubviews()jest wywoływana, zanim obiekt widoku ViewController wywoła swoją layoutSubviews()metodę
williamukoh,
28

Począwszy od iOS 6 i nowszych. Nowy schemat wygląda następująco:

wprowadź opis zdjęcia tutaj

Saad
źródło
1
Nazwij ten widok „A”. Rozważ drugi widok „B”, który pojawia się, gdy „A” znika. Czy „B.viewWillAppear” przed czy po „A.viewDidDisappear”? Czy istnieją sytuacje, w których kolejność tych dwóch zmian się zmienia?
ToolmakerSteve,
Wygląda na to, że pojawi się nowy widok (B) pojawi się przed zniknięciem. Na drugie pytanie. Potrzebujesz czasu, aby się temu przyjrzeć.
Saad
21

Skoncentrujmy się na metodach odpowiedzialnych za cykl życia UIViewController :

  • Kreacja:

    - (void)init

    - (void)initWithNibName:

  • Zobacz tworzenie:

    - (BOOL)isViewLoaded

    - (void)loadView

    - (void)viewDidLoad

    - (UIView *)initWithFrame:(CGRect)frame

    - (UIView *)initWithCoder:(NSCoder *)coder

  • Obsługa zmiany stanu widoku:

    - (void)viewDidLoad

    - (void)viewWillAppear:(BOOL)animated

    - (void)viewDidAppear:(BOOL)animated

    - (void)viewWillDisappear:(BOOL)animated

    - (void)viewDidDisappear:(BOOL)animated

    - (void)viewDidUnload

  • Obsługa ostrzeżeń pamięci:

    - (void)didReceiveMemoryWarning

  • Zwolnienie

    - (void)viewDidUnload

    - (void)dealloc

Schemat cyklu życia UIViewController

Aby uzyskać więcej informacji, zapoznaj się z dokumentacją klasy UIViewController .

Alexey Pelekh
źródło
19

Metody viewWillLayoutSubviewsi viewDidLayoutSubviewsnie są wymienione na schematach, ale są one wywoływane między viewWillAppeari viewDidAppear. Można je wywoływać wiele razy.

gjgjgj
źródło
Będą również wywoływane w innych momentach, gdy załadowane zostaną widoki podrzędne głównego widoku, na przykład, gdy załadowane zostaną komórki widoku tabeli lub widoku kolekcji.
ThomasW,
16

Odpowiedź Haidera jest poprawna dla wersji wcześniejszych niż iOS 6. Jednak od iOS 6 viewDidUnload i viewWillUnload nigdy nie są wywoływane. Docs stan: „Widoki nie są już oczyszczone w warunkach niskiej pamięci i tak ta metoda nie jest tzw.”

Matt Becker
źródło
Próbowałem umieścić punkt przerwania w ViewWillDisappear, ViewDidDisappear, Dispose. Ale żadne z nich nie zostało wywołane, gdy nawigowałem za pomocą metody PresentViewController (). Co może być przyczyną?
Sreeraj,
1
Link nie działa ... Co robi system operacyjny przy małej ilości pamięci?
Syn
Zapisuje je na dysku?
Ian Warburton,
16

Jest tu wiele nieaktualnych i niepełnych informacji. Tylko dla iOS 6 i nowszych :

  1. loadView[za]
  2. viewDidLoad[za]
  3. viewWillAppear
  4. viewWillLayoutSubviews jest to, że granice po raz pierwszy są finalizowane
  5. viewDidLayoutSubviews
  6. viewDidAppear
  7. * viewWillLayoutSubviews[b]
  8. * viewDidLayoutSubviews[b]

Przypisy:

(a) - Jeśli ręcznie nil swój pogląd w czasie didReceiveMemoryWarning, loadViewi viewDidLoadbędzie nazwany ponownie. Oznacza to, że domyślnie loadViewi viewDidLoadtylko jest wywoływana raz na widoku kontrolera instancji.

(b) Można nazwać dodatkowe 0 lub więcej razy.

bobiki
źródło
1
viewWillLayoutSubviewsi viewDidLayoutSubviewsbędzie również wywoływany w innych momentach, gdy załadowane zostaną widoki podrzędne głównego widoku, na przykład, gdy załadowane zostaną komórki widoku tabeli lub widoku kolekcji.
ThomasW,
11

Wyjaśnienie zmian stanu w oficjalnym dokumencie: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/index.html

Ten obraz pokazuje prawidłowe przejścia stanu między różnymi metodami wywołania zwrotnego „will” i „did”

Prawidłowe zmiany stanu:


Zaczerpnięte z: https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Art/UIViewController Class Reference_2x.png

Luismi
źródło
0

Zgodnie z dokumentem Apple'a - Rozpocznij tworzenie aplikacji na iOS (Swift) - Pracuj z kontrolerami widoku - Poznaj cykl życia kontrolera widoku

viewDidLoad()—Wywoływane, gdy widok zawartości kontrolera widoku (górna część jego hierarchii widoku) jest tworzony i ładowany ze scenorysu. … Użyj tej metody, aby przeprowadzić dowolną dodatkową konfigurację wymaganą przez kontroler widoku.

viewWillAppear()- Wywoływane tuż przed dodaniem widoku treści kontrolera widoku do hierarchii widoków aplikacji. Użyj tej metody, aby wyzwolić wszelkie operacje, które muszą zostać wykonane przed wyświetleniem widoku zawartości na ekranie

viewDidAppear()—Wywoływane zaraz po dodaniu widoku treści kontrolera widoku do hierarchii widoków aplikacji. Użyj tej metody, aby wyzwolić wszelkie operacje, które muszą nastąpić, gdy tylko widok zostanie wyświetlony na ekranie, takie jak pobieranie danych lub wyświetlanie animacji.

viewWillDisappear()- Wywoływane tuż przed usunięciem widoku treści kontrolera widoku z hierarchii widoków aplikacji. Ta metoda służy do wykonywania zadań czyszczenia, takich jak zatwierdzanie zmian lub rezygnacja ze statusu pierwszego odpowiadającego.

viewDidDisappear()- Wywoływane tuż po usunięciu widoku treści kontrolera widoku z hierarchii widoków aplikacji. Użyj tej metody, aby wykonać dodatkowe czynności porzucenia.

Fred
źródło