Kolejność inicjalizacji i ładowania UIViewController

Jestem całkiem nowy w programowaniu interfejsu użytkownika na Macu i iPhonie i natknąłem się na coś, co mnie nieco zastanawia.

UIViewController ma 3 metody, które wymagają inicjalizacji i jego widoku:

  1. init (i metody podobne do init)
  2. loadView
  3. viewDidLoad (metoda delegata)

Spodziewam się, że będą one występować w powyższej kolejności. Najpierw UIViewController jest alokowany przez jakiś inny obiekt, a następnie natychmiast wywoływany jest init (lub inny init method, like initWithStyle).

Dopiero po zainicjowaniu obiektu spodziewam się, że wywoła on własną funkcję loadView, po czym Widok, po załadowaniu, wywoła metodę delegata viewDidLoad.

Tak się nie dzieje, na przykład:

@implementation UIViewControllerSubclass

- (id)init {
        NSLog(@"0");
    if (self = [super init]) {
        NSLog(@"1");
    }
    return self;
}

- (void)loadView {
    [super loadView];
    NSLog(@"2");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"3");
}

@end

Wytwarza wyjście konsoli:

0
2
3
1

Metody loadView i viewDidLoad nie mogą więc wykonywać wywołań delegatów, ponieważ delegat jest zwykle ustawiany po wywołaniu na [super init], który (jak pokazano powyżej) jest wywoływany Po uruchomieniu loadView i viewDidLoad:

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] init];
[viewController setDelegate:self];

Jeśli chcę uruchomić kod, który w jakiś sposób ustawia Kontroler ViewController, powiadamiając delegata, czy kod powinien znajdować się w metodzie init? Czy nie istnieje powód, dla którego loadView pozwala na uruchomienie takiego kodu w odpowiednim momencie?

Wygląda na to, że będę musiał utworzyć nową metodę initWithDelegate, która ustawia delegata ivar przed wywołaniem [super init]. to w złą stronę?

Z góry dzięki:)

Author: Peter Hosey, 2010-01-13

5 answers

System ładowania widoku na iPhonie działa tak:

Kiedy inicjalizujesz kontroler widoku (albo-INIT albo-initwithnibname: bundle:), nie tworzy on i nie inicjalizuje widoku. Gdy wywołujesz-view po raz pierwszy, wywołuje-loadView. Domyślnie-loadView wczytuje widok z pliku xib (nibName). Jeśli jednak nadpiszesz tę opcję, będziesz odpowiedzialny za utworzenie widoku i przypisanie go do właściwości view kontrolera widoku. Jako przykład:

- (void)loadView
{
   UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
   // add subviews 
   self.view = view;
   [view release];
}

Za każdym razem, gdy tworzysz Widok, który różni się od widoku, który staje się widoczny i wyświetlany na ekranie , wywołuje -viewDidLoad. (- viewDidAppear / - viewdiddisappear służy do widoczności widoku na ekranie)

Ponieważ jesteśmy już poza ścieżką, rozważmy zarządzanie pamięcią. Gdy widok jest poza ekranem, system automatycznie ustawi właściwość widok kontrolera widoku na zero. Problem polega na tym, że wyciekają wszystkie podglądy tego widoku. Jak to? Cóż, liczba zatrzymanych dla każdego subview wynosi 2 (widoki zachowują podview, a kontroler widoku ma wyjście / ivar do niego). Gdy widok jest zerowy, liczba zatrzymań tego widoku wynosi 1. Nie ma sensu, aby Widok pozostawał w pobliżu, Jeśli widok nie jest wyświetlany, więc ustawiasz go na nil in-viewDidUnload (co jest Hookiem za każdym razem, gdy widok jest ustawiony na nil).

 30
Author: Sr.Richie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-09 16:16:44

Metoda initwithnibname:bundle: jest wyznaczonym inicjalizatorem dla klasy UIViewController.

Spróbuj przesłonić i użyć go zamiast init:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
    }
    return self;
}

...

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] initWithNibName:@"UIViewControllerSubclass" bundle:nil];
 16
Author: gerry3,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-13 00:32:11
-(void)awakeFromNib
{
}

Jest wywoływane tylko wtedy, gdy używasz tablicy wątków do przechowywania kontrolera widoku narysowanego w tablicy wątków Stalówka - - - oznacza pakiet interfejsu.

Prawidłowa Sekwencja to

-(void)initWithCoder
-(void)awakefromNib    //(if story board is used)
    or
-(void)loadView----() //if manually generating the view contoller

-(void)viewDidLoad-----(called only once in the life cycle of viewController)
-(void)viewWillAppear
-(void)viewDidAppear

Podczas przechodzenia do nowego Viewcontrollera

-(void)viewWillDisappear
-(void)viewDidDisappear

Podczas powrotu do pierwszego kontrolera Viewcontrollera

-(void)viewWillAppear
-(void)viewDidAppear
 13
Author: Sauvik Dolui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-11 10:03:25

Gerry3 ma rację. Te rzeczy wciąż mnie mylą. Sprawdź dokumenty na wyznaczonych inicjalizatorów .

Zauważ również, że jeśli twój kontroler jest tworzony przez ładowany nib, to tylko initWithCoder zostanie wywołany. w takim przypadku loadView również nie jest wywoływany.

Z tego powodu wydaje się, że większość kodu, który widziałem, wykonuje większość inicjalizacji w takich rzeczach jak viewDidLoad, chociaż wydaje się to złe, ale wydaje się być najlepszą metodą, która zostanie wywołana w obu przypadkach gdzie coś jest ładowane do Stalówki i tworzone programowo.

Ale powodem, dla którego wydaje się to nie w porządku, jest to, że [super init] wywołuje loadView itp. –

 4
Author: Nimrod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-08 09:14:07

Biorąc pod uwagę sugestię @ Nimrod zrobiłem coś takiego:

-(void)viewDidLoad
{
    // Init code here
}

Nie wiem, czy może to powodować problemy z wyciekiem pamięci, ale patrząc na dokumenty Apple, nie wydaje się tworzyć żadnego cyklu:

Wyświetl cykl życia http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Art/loading_a_view_into_memory.jpg

To zostało wzięte z: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW1

 0
Author: bitoiu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-09 21:44:23