iPhone SDK: jaka jest różnica między loadView i viewDidLoad?

136

Czy podczas pracy z widokami i kontrolerami widoku w aplikacji na iPhone'a ktoś może wyjaśnić różnicę między loadView i viewDidLoad?

Mój osobisty kontekst jest taki, że wszystkie moje widoki tworzę z kodu, nie używam i nie będę używać Interface Builder, jeśli to coś zmieni.

Zauważyłem, że często, gdy dodaję kod init do loadView, kończę z nieskończonym śladem stosu, więc zwykle wykonuję wszystkie moje budowanie widoku podrzędnego w viewDidLoad ... ale naprawdę nie jest dla mnie jasne, kiedy każdy z nich zostanie wykonany, i jakie jest bardziej odpowiednie miejsce do umieszczenia kodu inicjującego. Idealny byłby prosty schemat wywołań inicjalizacyjnych.

Dzięki!

ryan.scott
źródło

Odpowiedzi:

200

Domyślam się, w czym może być problem, ponieważ zrobiłem to:

Zauważyłem, że często, gdy dodaję kod init do loadView, otrzymuję nieskończony ślad stosu

Nie czytaj self.view w -loadView. Tylko ustaw , nie rozumiem .

Akcesor właściwości self.view wywołuje -loadView, jeśli widok nie jest aktualnie załadowany. Jest twoja nieskończona rekurencja.

Zwykły sposób programistycznego tworzenia widoku w -loadView, jak pokazano w przykładach Apple przed interfejsem Builder, jest bardziej podobny do tego:

UIView *view = [[UIView alloc] init...];
...
[view addSubview:whatever];
[view addSubview:whatever2];
...
self.view = view;
[view release];

I nie winię cię za to, że nie używasz IB. Utknąłem przy tej metodzie dla całego Instapapera i czuję się z nią znacznie wygodniej niż radzenie sobie ze złożonością IB, dziwactwami interfejsu i nieoczekiwanym zachowaniem za kulisami.

Marco
źródło
Ach, wreszcie dziękuję za wyjaśnienie! Odwróciłem się od idiomu przydzielania tymczasowej zmiennej, a następnie ustawiania na self.view, a następnie zwalniania ... wydawało się to niezręczne, niepotrzebne. Teraz rozumiem, dlaczego ta decyzja poprowadziłaby mnie na ścieżkę, na której się teraz znajduję.
ryan.scott
Mam taki kod i nie ma rekursji. czemu? -(void) loadView { // Frame for Hypnosis view CGRect frame = [[UIScreen mainScreen] bounds]; // Create a Hipnosis view v = [[HypnosisView alloc] initWithFrame:frame]; self.view = v;
user2054339
44

loadViewjest metodą UIViewController, która faktycznie załaduje widok i przypisze go do viewwłaściwości. Jest to również lokalizacja, którą podklasa klasy UIViewControllerzastąpiłaby, gdybyś chciał programowo skonfigurować viewwłaściwość.

viewDidLoadto metoda wywoływana po załadowaniu widoku. Jest to wywoływane po wywołaniu loadView. Jest to miejsce, w którym można nadpisać i wstawić kod, który wykonuje dalszą wstępną konfigurację widoku po jego załadowaniu.

NilObject
źródło
14
viewDidLoad()

ma być używany, gdy ładujesz widok z NIB i chcesz wykonać dowolne dostosowanie po uruchomieniu

LoadView()

ma być używany, gdy chcesz stworzyć widok programowo (bez użycia Interface Builder)

ashokdy
źródło
To może mieć jakiś problem, mam test, gdy mój kontroler widoku nie był skojarzony z plikiem NIB, nadal nazywa się
viewDidLoad
11

Wystarczy dodać kilka przykładów kodu, aby zademonstrować, co powiedział NilObject:

- (void)loadView
{
    // create and configure the table view
    myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame] style:UITableViewStyleGrouped];   
    myTableView.delegate = self;
    myTableView.dataSource = self;
    myTableView.scrollEnabled = NO;
    self.view = myTableView;

    self.view.autoresizesSubviews = YES;
}

- (void)viewDidLoad 
{
  self.title = @"Create group";

  // Right menu bar button is to Save
  UIBarButtonItem *saveButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Save" style:UIBarButtonItemStyleDone target:self action:@selector(save)];
  self.navigationItem.rightBarButtonItem = saveButtonItem;
  [saveButtonItem release];
}
alamodey
źródło
4
więc między wami dwojgiem, czy słuszne jest stwierdzenie, że loadView jest miejscem, w którym powinienem dokonać alokacji / inicjalizacji self.view mojego kontrolera, a widoki potomne powinny być obsługiwane w viewDidLoad (lub później)?
ryan.scott
2

Aby zapobiec powstawaniu nieskończonej pętli podczas czytania self.view, wywołaj super implementację klasy podczas ładowania widoku. Super implementacja przydzieli Ci nowy UIView.

- (void) loadView {
[super loadview];

// init code here...

[self.view addSubView:mySubview1]; //etc..

}
futureelite7
źródło
6
Mógłbym przysiąc, że dokumentacja Apple mówi, że nie powinieneś dzwonić [super loadView];. Zaprzeczono temu w przykładach, ale myślę, że doktorzy powiedzieli to poprawnie (znalazłem wiele błędów w przykładach w czasie). [super loadView]jest jednak potrzebny dla UITableViewController itp. Jednak! Wszelkie ustawienia po załadowaniu (np. Dodawanie dodatkowych podglądów podrzędnych) powinny być wykonywane w viewDidLoad.
Ivan Vučica
Jak dotąd wywołałem [super loadView] bez żadnych skutków ubocznych. Może to być prawdą, jeśli zamierzasz ustawić pogląd na siebie na coś, co sam stworzyłeś.
futureelite7
Jeśli wywołasz [super loadView] wewnątrz loadView, wtedy spróbuje załadować widok z końcówki, jeśli jest dostępna z domyślną nazwą. Musisz więc uważać.
Ian1971
A jeśli wywołasz [super loadView], inicjalizujesz self.view metodą super loadView
Alex Nazarsky,
1

Najłatwiejszym sposobem użycia loadView jest utworzenie pewnego typu kontrolera widoku podstawowego, takiego jak MyBaseViewController, który jest podklasą UIViewController. W jego metodzie loadView stwórz widok w ten sposób:

-(void) loadView {
    if ([self viewFromNib]) {
        self.view = [self viewFromNib];
    } else {
        self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    }
    self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight;
    self.view.backgroundColor = [UIColor whiteColor];
}

A kiedy potrzebujesz stworzyć jakiś kontroler widoku, po prostu użyj podklasy MyBaseViewController iw jego kontrolerze loadView po prostu wywołaj [super loadView] w ten sposób

//sucblass loadView
-(void) loadView {
    [super loadView];

    //rest of code like this..
    UILabel *myLabel = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:myLabel];
    [myLabel release];
}
Josip B.
źródło
1

loadView()jest wywoływana, gdy kontroler jest proszony o utworzenie pliku self.view. Możesz to zrobić samodzielnie

self.view = [UIView alloc] init...];

Albo klasa nadrzędna UIController kontrolera ma już nazwę metody, -loadView()która inicjuje widok self.view w pustym widoku. Wtedy możesz zadzwonić

[super loadView];

Naprawdę polecam drugie podejście, ponieważ zachęca ono do dziedziczenia. Tylko wtedy, gdy kontroler widoku nie jest bezpośrednio dziedziczony po UIViewController.

Dulguun Otgon
źródło
0

Definicja podana przez Apple w viewDidLoad wspomina, że ​​jest wywoływana po załadowaniu widoku kontrolera do pamięci. Mówiąc prościej, jest to pierwsza metoda, która zostanie załadowana.

Być może zastanawiasz się, pod jakim warunkiem ta metoda zostanie w pełni wykorzystana? Odpowiedź brzmi: w zasadzie wszystko, co chcesz, aby aplikacja załadowała się jako pierwsza. Na przykład możesz chcieć mieć inny kolor tła zamiast białego, być może możesz wybrać niebieski.

Gulsan Borbhuiya
źródło