programowanieProgramista iOS

Opisz cykl życia view controllera w UIKit oraz jak nieprawidłowe zarządzanie tym cyklem może prowadzić do wycieków pamięci lub błędów w UI. Jakie szczegóły warto znać?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

Cykl życia UIViewController obejmuje kluczowe metody:

  • init(nibName:bundle:) / init(coder:): inicjalizacja
  • loadView: tworzenie hierarchii widoków
  • viewDidLoad: widok został załadowany (idealne miejsce do wstępnej konfiguracji)
  • viewWillAppear / viewDidAppear: widok pokazuje/jest pokazany
  • viewWillDisappear / viewDidDisappear: widok znika/jest schowany
  • deinit: usunięcie kontrolera

Kolejność wywołania metod:

  • Najpierw tworzy się hierarchia widoków (loadView, a następnie viewDidLoad)
  • Przy każdym pojawieniu się na ekranie i zniknięciu wywoływane są viewWillAppear/viewWillDisappear, następnie viewDidAppear/viewDidDisappear
  • Po usunięciu — deinit

Szczegóły:

  • W viewDidLoad nie należy odnosić się do rozmiarów widoków — mogą być one nieaktualne
  • Ważne jest zwalnianie zasobów (obserwatory, timery) w deinit lub viewWillDisappear
  • Dodawanie subwidoków — w viewDidLoad, ale nie w viewWillAppear — w przeciwnym razie może dojść do duplikacji przy każdym pojawieniu się

Przykład:

class MyViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setupViews() setupBindings() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Subskrybuj powiadomienia } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // Wypisz się z powiadomień } deinit { // Oczyszczenie } }

Pytanie podchwytliwe

Pytanie:

Czy widok kontroler może odnosić się do właściwości widoku poza cyklem życia (np. w inicjatorze)?

Odpowiedź: Nie, przed wywołaniem (lub nadpisaniem) loadView wszystkie właściwości związane z widokiem mogą być nieinicjalizowane. Jakikolwiek dostęp do nich poza loadView/viewDidLoad spowoduje awarię.

Przykład:

// Błąd: self.view jeszcze nie zainicjalizowane! init() { super.init(nibName: nil, bundle: nil) self.view.backgroundColor = .red //AWARIA }

Przykłady rzeczywistych błędów wynikających z niewiedzy na temat szczegółów tematu


Historia

Projekt się zawieszał z powodu przedwczesnego odwoływania się do self.view w init — widok nie został stworzony, co prowadziło do awarii.


Historia

W dużych projektach zapominali o wypisaniu się z NotificationCenter lub delegate w viewWillDisappear i/lub deinit, co prowadziło do wycieków pamięci (NotificationCenter odnosił się do view controller, ten nie był usuwany i nadal słuchał zdarzeń).


Historia

W viewWillAppear przy każdym pojawieniu się dodawano nowe subwidoki do widoku (na przykład, pokazywano wskaźnik ładowania), nie sprawdzając istnienia. W rezultacie przy każdym powrocie na ekran pojawiało się coraz więcej duplikujących się wskaźników, UI przestawał działać.