iPhone SDK: qual è la differenza tra loadView e viewDidLoad?


136

Quando si lavora con le visualizzazioni e i controller di visualizzazione in un'app per iPhone, qualcuno può spiegare la differenza tra loadView e viewDidLoad?

Il mio contesto personale è che costruisco tutte le mie visualizzazioni dal codice, non uso e non userò Interface Builder, se ciò dovesse fare la differenza.

Ho scoperto che spesso quando aggiungo il codice di inizializzazione a loadView, finisco con una traccia dello stack infinita, quindi in genere faccio tutto il mio edificio di vista figlio in viewDidLoad ... ma non è molto chiaro per me quando ognuno viene eseguito, e qual è il posto più appropriato per inserire il codice di inizializzazione. Ciò che sarebbe perfetto, è un semplice diagramma delle chiamate di inizializzazione.

Grazie!

Risposte:


200

Posso indovinare quale potrebbe essere il problema qui, perché l'ho fatto:

Ho scoperto che spesso quando aggiungo il codice init a loadView, finisco con una traccia dello stack infinita

Non leggere self.view in -loadView. Solo insieme , non lo ottenere esso.

L'accessorio self.view chiama -loadView se la vista non è attualmente caricata. C'è la tua ricorsione infinita.

Il solito modo di costruire la vista a livello di codice in -loadView, come dimostrato negli esempi pre-Interface-Builder di Apple, è più simile a questo:

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

E non ti biasimo per non aver usato IB. Ho aderito a questo metodo per tutti gli Instapaper e mi trovo molto più a mio agio con esso rispetto alle complessità di IB, alle stranezze dell'interfaccia e al comportamento inaspettato dietro le quinte.


ahhhh, grazie per una spiegazione, finalmente! Mi sono allontanato dall'idioma di allocare una variabile temporanea, quindi impostare su self.view, quindi rilasciare ... sembrava in qualche modo imbarazzante, inutile. Ora posso capire perché quella decisione mi avrebbe condotto lungo il percorso in cui ora mi trovo.
ryan.scott,

Ho un tale codice e non c'è ricorsione. perché? -(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

loadViewè il metodo in UIViewControllercui verrà effettivamente caricata la vista e assegnata alla viewproprietà. Questa è anche la posizione in cui una sottoclasse UIViewControlleravrebbe la precedenza se si desidera impostare la viewproprietà a livello di codice .

viewDidLoadè il metodo che viene chiamato una volta caricata la vista. Questo viene chiamato dopo che viene chiamato loadView. È un luogo in cui è possibile sovrascrivere e inserire il codice che esegue un'ulteriore configurazione iniziale della vista una volta caricata.


14
viewDidLoad()

deve essere utilizzato quando si carica la vista da un NIB e si desidera eseguire qualsiasi personalizzazione dopo l'avvio

LoadView()

deve essere utilizzato quando si desidera creare la vista a livello di codice (senza l'uso di Interface Builder)


Questo potrebbe avere qualche problema, ho un test quando il mio controller di visualizzazione non era associato al file NIB, viewDidLoad ancora chiamato
Ruandao

11

Basta aggiungere alcuni esempi di codice per dimostrare ciò che NilObject ha detto:

- (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];
}

4
quindi, tra voi due, è corretto affermare che loadView è dove dovrei fare l'allocazione / init della self.view del mio controller, e le viste figlio dovrebbero essere gestite in viewDidLoad (o successive)?
ryan.scott,

2

Per evitare che si verifichi un ciclo infinito quando leggi self.view, chiama la super implementazione della classe quando carichi una vista. La super implementazione assegnerà una nuova UIView per te.

- (void) loadView {
[super loadview];

// init code here...

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

}

6
Potrei giurare che la documentazione di Apple diceva che non dovresti chiamare [super loadView];. Ciò era contraddetto negli esempi, ma penso che i documenti lo dicessero correttamente (ho trovato numerosi bug negli esempi nel tempo). [super loadView]è necessario per UITableViewController ecc. Però! Qualsiasi impostazione post-caricamento (ad es. Aggiunta di ulteriori visualizzazioni secondarie) deve essere eseguita in viewDidLoad.
Ivan Vučica,

Finora ho chiamato [super loadView] senza effetti collaterali. Può essere vero se hai intenzione di impostare self.view a qualcosa che ti sei fatto però.
futureelite7

Se si chiama [super loadView] all'interno di loadView, tenterà di caricare la vista da un pennino se disponibile con il nome predefinito. Quindi devi stare attento.
Ian1971,

E se chiami [super loadView], inizializzi self.view nel metodo super loadView
Alex Nazarsky

1

Il modo più semplice per utilizzare loadView è creare un tipo di controller di visualizzazione di base, come MyBaseViewController che è una sottoclasse di UIViewController. Nel suo metodo loadView crea la vista in questo modo:

-(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];
}

E quando è necessario creare un controller di visualizzazione, basta usare la sottoclasse di MyBaseViewController e nel suo controller loadView si chiama semplicemente [super loadView] in questo modo

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

    //rest of code like this..
    UILabel *myLabel = [[UILabel alloc] initWithFrame:myFrame];
    [self.view addSubview:myLabel];
    [myLabel release];
}

1

loadView()viene chiamato quando viene richiesto al controller di crearne uno self.view. Puoi farlo da solo come

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

Oppure la classe UIController principale del controller ha già un nome metodo -loadView()che inizializza self.view in una vista vuota. Quindi puoi chiamare

[super loadView];

Consiglio vivamente il secondo approccio in quanto incoraggia l'eredità. Solo se il controller della vista non è ereditato direttamente da UIViewController.


0

La definizione fornita da Apple su viewDidLoad ha indicato che viene chiamato dopo che la vista del controller è stata caricata in memoria. Per dirla in parole povere, è il primo metodo che verrà caricato.

Potresti pensare a quale condizione verrà pienamente utilizzato questo metodo? La risposta è, praticamente qualunque cosa tu abbia voluto caricare prima l'app. Ad esempio, potresti desiderare un colore di sfondo diverso, invece del bianco, potresti forse scegliere il blu.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.