Wie funktioniert View Controller Containment in iOS 5?

108

In der WWDC 2011 Session 102 führte Apple - View - Controller Containment, das ist die Fähigkeit, benutzerdefinierte - View - Controller - Container, analog zu schaffen UITabBarController, UINavigationControllerund dergleichen.

Ich habe mir die Beispiele mehrmals angesehen. Es gibt eine Reihe von Methoden, die mit diesem Muster verbunden sind, aber es war ein wenig schwierig, sie genau herauszufinden. Ich werde hier posten, was meiner Meinung nach vor sich geht, und sehen, ob die Community meinen Verdacht bestätigt oder nicht bestätigt.

Szenario 1: Wechsel von keinem übergeordneten zu einem neuen übergeordneten Ansichtscontroller

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Müssen die ersten beiden Zeilen in der angegebenen Reihenfolge auftreten oder können sie umgekehrt werden?

Szenario 2: Wechsel von einem übergeordneten Ansichtscontroller zu keinem übergeordneten Ansichtscontroller

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

Muss man auch anrufen [vc didMoveToParentViewController:nil]? Die Beispiele in Sitzung 102 haben dies in diesem Szenario nicht getan , aber ich weiß nicht, ob dies eine Auslassung war oder nicht.

Szenario 3: Wechseln von einem übergeordneten Ansichtscontroller zu einem anderen

Dies wird wahrscheinlich auf folgende Weise geschehen, da die Logik in jedem übergeordneten Ansichtscontroller gekapselt wird.

// In the old parent
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

// In the new parent
[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];

Fragen

Meine Hauptfrage lautet: Sollte View Controller-Containment im Allgemeinen so funktionieren? Sind die oben angegebenen Mechaniken korrekt?

Ist es notwendig anzurufen, willMoveToParentViewControllerbevor Sie anrufen addChildViewController? Dies scheint mir die logische Reihenfolge zu sein, aber ist es unbedingt notwendig?

Ist es notwendig , rufen didMoveToParentViewController:nilnach dem Aufruf removeFromParentViewController?

Gregory Higley
quelle

Antworten:

72

In den UIViewControllerDokumenten ist ziemlich klar, wann und wann nicht willMove/ didMoveMethoden aufgerufen werden sollen. Lesen Sie die Dokumentation "Implementieren eines Container View Controllers" .

In den Dokumenten heißt es, dass Sie die Methode addChildViewControllernicht aufrufen müssen , wenn Sie sie nicht überschreiben willMoveToParentViewController:. Sie müssen die didMoveToParentViewController:Methode jedoch nach Abschluss des Übergangs aufrufen . "Ebenso liegt es in der Verantwortung des Container View Controllers, die willMoveToParentViewController:Methode vor dem Aufruf der removeFromParentViewControllerMethode aufzurufen . Die removeFromParentViewControllerMethode ruft die didMoveToParentViewController:Methode des Child View Controllers auf."

Außerdem gibt es ein Beispiel herausgearbeitet hier und Beispielcode hier .

Viel Glück

timthetoolman
quelle
17
Ich verstehe, addChildViewControllersollte also ausgeglichen sein didMoveToParentViewControllerund willMoveToParentViewControllersollte ausgeglichen sein mit removeFromParentViewController. Genau das habe ich gesucht. Ich bin mir nicht sicher, wie ich es in den Dokumenten verpasst habe.
Gregory Higley
Warum nicht? Warum müssen Sie nicht willMoveToParentViewController aufrufen, sondern didMoveToParentViewController aufrufen?
user4951
Denn das sagen die Dokumente. Apple hat offensichtlich das Gefühl, dass wir es nicht wissen müssen.
7
Der Grund ist der Animation zuliebe: Angenommen, Sie erstellen Ihren eigenen Navigationscontroller. Zu Beginn einer Slide-In-Animation muss 'willMove' aufgerufen werden, und am Ende der Animation muss 'didMove' aufgerufen werden. Wenn Sie jetzt zu Beginn der Animation 'addChild' aufrufen, wird automatisch 'willMove' für Sie aufgerufen. Es kann jedoch nicht wissen, wann die Animation (falls vorhanden) beendet ist. Daher müssen Sie am Ende der Animation (oder sofort ohne Animation) manuell 'didMove' aufrufen.
Chris
2
Und für eine "Slide-Out" -Animation, z. B. wenn das Kind entfernt wird, müssen Sie zu Beginn der Animation "willMove" manuell aufrufen, da uikit sonst nicht wissen würde, wann Sie die "viewWillDisappear" Ihres Kinder-VC aufrufen sollen. Und am Ende der Animation, wenn Sie removeFromParentViewController aufrufen, kann es automatisch 'didMove' für Sie aufrufen.
Chris
23

Dieser Teil ist nicht korrekt:

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Laut den Dokumenten:

Wenn Ihr benutzerdefinierter Container die Methode addChildViewController: aufruft, ruft er automatisch die Methode willMoveToParentViewController: des Ansichtscontrollers auf, der als untergeordnetes Element hinzugefügt werden soll, bevor er hinzugefügt wird.

Sie brauchen den [vc willMoveToParentViewController:self]Anruf also nicht . Dies geschieht automatisch, wenn Sie anrufen [self addChildViewController:vc]. Hier ist noch einmal das Codebeispiel:

[self addChildViewController:vc];
// [vc willMoveToParentViewController:self] called automatically
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

So entfernen Sie View Controller:

Die removeFromParentViewController-Methode ruft automatisch die didMoveToParentViewController: -Methode des untergeordneten Ansichtscontrollers auf, nachdem das untergeordnete Element entfernt wurde.

Vermutlich ist dieser Anruf [oldVC didMoveToParentViewController:nil].

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
// [vc didMoveToParentViewController:nil] called automatically
Nevan König
quelle
Wenn dies anders gemacht wird, wird der PresentViewController nicht auf dem PresentedViewController festgelegt, auch wenn dies anscheinend funktioniert.
Adrian
Die Dokumente sagen, dass der Aufruf didMoveToParentViewController " unmittelbar nach dem Aufrufen der Methode addChildViewController:" nicht angibt, wann Sie die untergeordnete Unteransicht tatsächlich hinzufügen. Ich frage mich, ob jeder das falsch verstanden hat. Gibt es in einigen Apple Docs ein Beispiel, anhand dessen wir dies überprüfen können?
Robert
Hinweis: Sie tun müssen anrufen , willMoveToParentViewControllerum vor addChildViewControllerwenn das ausgewählte Element bewegt werden , ist eine benutzerdefinierte Klasse mit überschriebene addChildViewController(es sei denn , der Überschreibung nennt es intern)
bunkerdive