iPhone SDK: Was ist der Unterschied zwischen loadView und viewDidLoad?

136

Kann jemand beim Arbeiten mit Ansichten und Ansichtscontrollern in einer iPhone-App den Unterschied zwischen loadView und viewDidLoad erklären?

Mein persönlicher Kontext ist, dass ich alle meine Ansichten aus Code erstelle. Ich verwende und werde Interface Builder nicht verwenden, sollte dies einen Unterschied machen.

Ich habe festgestellt, dass ich beim Hinzufügen von Init-Code zu loadView häufig eine unendliche Stapelverfolgung erhalte, sodass ich normalerweise alle meine untergeordneten Ansichten in viewDidLoad erstelle ... aber es ist mir wirklich unklar, wann jeder ausgeführt wird, und Was ist der geeignetere Ort, um Init-Code zu setzen. Was perfekt wäre, ist ein einfaches Diagramm der Initialisierungsaufrufe.

Vielen Dank!

ryan.scott
quelle

Antworten:

200

Ich kann mir vorstellen, was hier das Problem sein könnte, weil ich es getan habe:

Ich habe festgestellt, dass ich beim Hinzufügen von Init-Code zu loadView häufig eine unendliche Stapelverfolgung erhalte

Lesen Sie self.view nicht in -loadView. Nur setzen sie, nicht bekommen es.

Der Eigenschafts-Accessor self.view ruft -loadView auf, wenn die Ansicht derzeit nicht geladen ist. Es gibt deine unendliche Rekursion.

Die übliche Methode zum programmgesteuerten Erstellen der Ansicht in -loadView, wie in den Beispielen vor dem Interface-Builder von Apple gezeigt, sieht folgendermaßen aus:

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

Und ich beschuldige Sie nicht, IB nicht verwendet zu haben. Ich habe mich bei Instapaper an diese Methode gehalten und finde mich damit viel wohler als mit der Komplexität von IB, den Macken der Benutzeroberfläche und dem unerwarteten Verhalten hinter den Kulissen.

Marco
quelle
ahhhh, danke für eine Erklärung, endlich! Ich habe mich vor der Redewendung gescheut, eine temporäre Variable zuzuweisen, dann auf self.view zu setzen und dann freizugeben ... es schien irgendwie umständlich, unnötig. Ich kann jetzt verstehen, warum diese Entscheidung mich auf den Weg geführt hätte, auf dem ich mich jetzt befinde.
Ryan.scott
Ich habe einen solchen Code und es gibt keine Rekursion. Warum? -(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

loadViewist die Methode UIViewController, mit der die Ansicht tatsächlich geladen und der viewEigenschaft zugewiesen wird . Dies ist auch der Speicherort, den eine Unterklasse UIViewControllerüberschreiben würde, wenn Sie die viewEigenschaft programmgesteuert einrichten möchten .

viewDidLoadist die Methode, die aufgerufen wird, sobald die Ansicht geladen wurde. Dies wird aufgerufen, nachdem loadView aufgerufen wurde. Hier können Sie Code überschreiben und einfügen, der die Ansicht nach dem Laden weiter initialisiert.

NilObject
quelle
14
viewDidLoad()

wird verwendet, wenn Sie Ihre Ansicht von einer NIB laden und nach dem Start Anpassungen vornehmen möchten

LoadView()

wird verwendet, wenn Sie Ihre Ansicht programmgesteuert erstellen möchten (ohne die Verwendung von Interface Builder).

Ashokdy
quelle
Dies kann ein Problem haben. Ich habe einen Test, als mein View Controller nicht mit der NIB-Datei verknüpft war. ViewDidLoad wird immer noch aufgerufen
ruandao
11

Fügen Sie einfach einige Codebeispiele hinzu, um zu demonstrieren, was NilObject gesagt hat:

- (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
quelle
4
Ist es also zwischen Ihnen beiden richtig zu sagen, dass in loadView die Zuweisung / Initialisierung der self.view meines Controllers erfolgen soll und untergeordnete Ansichten in viewDidLoad (oder höher) behandelt werden sollen?
Ryan.scott
2

Um zu verhindern, dass beim Lesen von self.view eine Endlosschleife auftritt, rufen Sie beim Laden einer Ansicht die Super-Implementierung der Klasse auf. Die Super-Implementierung weist Ihnen eine neue UIView zu.

- (void) loadView {
[super loadview];

// init code here...

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

}
futureelite7
quelle
6
Ich könnte schwören, dass Apples Dokumentation besagt, dass Sie nicht anrufen sollten [super loadView];. Dies wurde in den Beispielen widersprochen, aber ich denke, die Dokumente haben es richtig gesagt (ich habe im Laufe der Zeit zahlreiche Fehler in Beispielen gefunden). [super loadView]wird jedoch für UITableViewController usw. benötigt. Jedoch! Alle Einstellungen nach dem Laden (z. B. Hinzufügen zusätzlicher Unteransichten) sollten in viewDidLoad erfolgen.
Ivan Vučica
Ich habe [super loadView] bisher ohne Nebenwirkungen aufgerufen. Es kann wahr sein, wenn Sie beabsichtigen, self.view auf etwas zu setzen, das Sie selbst gemacht haben.
futureelite7
Wenn Sie [super loadView] in loadView aufrufen, wird versucht, die Ansicht von einer Schreibfeder zu laden, sofern diese mit dem Standardnamen verfügbar ist. Sie müssen also vorsichtig sein.
Ian1971
Und wenn Sie [super loadView] aufrufen, initialisieren Sie self.view in der super loadView-Methode
Alex Nazarsky
1

Die einfachste Möglichkeit, loadView zu verwenden, besteht darin, eine Art Basisansichts-Controller wie MyBaseViewController zu erstellen, der eine Unterklasse von UIViewController ist. Erstellen Sie in der loadView-Methode die Ansicht folgendermaßen:

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

Und wenn Sie einen View-Controller erstellen müssen, verwenden Sie einfach die Unterklasse von MyBaseViewController und rufen in seinem loadView-Controller einfach [super loadView] so auf

//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.
quelle
1

loadView()wird aufgerufen, wenn Ihr Controller aufgefordert wird, seine zu erstellen self.view. Sie können es gerne selbst machen

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

Oder die übergeordnete UIController-Klasse Ihres Controllers hat bereits einen Methodennamen, -loadView()der Ihre self.view in eine leere Ansicht initialisiert. Dann können Sie anrufen

[super loadView];

Ich empfehle den zweiten Ansatz wirklich, da er die Vererbung fördert. Nur wenn Ihr View Controller nicht direkt von UIViewController geerbt wird.

Dulguun Otgon
quelle
0

In der von Apple in viewDidLoad angegebenen Definition wurde erwähnt, dass sie aufgerufen wird, nachdem die Ansicht des Controllers in den Speicher geladen wurde. Einfach ausgedrückt ist es die erste Methode, die geladen wird.

Sie denken vielleicht, unter welchen Bedingungen diese Methode vollständig genutzt wird? Die Antwort lautet: Was auch immer die App zuerst laden soll. Zum Beispiel möchten Sie vielleicht eine andere Hintergrundfarbe anstelle von Weiß, Sie könnten vielleicht Blau wählen.

Gulsan Borbhuiya
quelle