Ich tauche gerade zum ersten Mal in die iOS-Entwicklung ein, und eines der ersten Dinge, die ich tun musste, ist die Implementierung eines benutzerdefinierten Container-View-Controllers - nennen wir es SideBarViewController
-, der austauscht, welcher von mehreren möglichen untergeordneten View-Controllern es ist zeigt, fast genau wie ein Standard Tab Bar Controller . (Es ist so ziemlich ein Tab Bar Controller, aber mit einem versteckten Seitenmenü anstelle einer Tab Bar.)
addChildViewController
Gemäß den Anweisungen in der Apple-Dokumentation rufe ich jedes Mal auf , wenn ich meinem Container einen untergeordneten ViewController hinzufüge. Mein Code zum Austauschen des aktuellen untergeordneten Ansichts-Controllers SideBarViewController
sieht folgendermaßen aus:
- (void)showViewController:(UIViewController *)newViewController {
UIViewController* oldViewController = [self.childViewControllers
objectAtIndex:0];
[oldViewController removeFromParentViewController];
[oldViewController.view removeFromSuperview];
newViewController.view.frame = CGRectMake(
0, 0, self.view.frame.size.width, self.view.frame.size.height
);
[self addChildViewController: newViewController];
[self.view addSubview: newViewController.view];
}
Dann fing ich an herauszufinden, was addChildViewController
hier passiert, und mir wurde klar, dass ich keine Ahnung habe. Abgesehen davon, dass das Neue ViewController
in das .childViewControllers
Array eingefügt wird, scheint es keine Auswirkungen auf irgendetwas zu haben. Aktionen und Ausgänge aus der Sicht des untergeordneten Controllers zum untergeordneten Controller, die ich im Storyboard festgelegt habe, funktionieren auch dann noch einwandfrei addChildViewController
, wenn ich nie anrufe , und ich kann mir nicht vorstellen, was sich sonst noch darauf auswirken könnte.
In der Tat, wenn ich meinen Code umschreibe, um nicht aufzurufen addChildViewController
, und stattdessen so aussehe ...
- (void)showViewController:(UIViewController *)newViewController {
// Get the current child from a member variable of `SideBarViewController`
UIViewController* oldViewController = currentChildViewController;
[oldViewController.view removeFromSuperview];
newViewController.view.frame = CGRectMake(
0, 0, self.view.frame.size.width, self.view.frame.size.height
);
[self.view addSubview: newViewController.view];
currentChildViewController = newViewController;
}
... dann funktioniert meine App immer noch perfekt, soweit ich das beurteilen kann!
Die Apple-Dokumentation gibt nicht viel Aufschluss darüber, was addChildViewController
funktioniert oder warum wir es nennen sollen. Der gesamte Umfang der relevanten Beschreibung dessen, was die Methode tut oder warum sie in ihrem Abschnitt in der UIViewController
Klassenreferenz verwendet werden sollte, ist derzeit:
Fügt den angegebenen Ansichts-Controller als untergeordnetes Element hinzu. ... Diese Methode soll nur von einer Implementierung eines benutzerdefinierten Container View Controllers aufgerufen werden. Wenn Sie diese Methode überschreiben, müssen Sie in Ihrer Implementierung super aufrufen.
Es gibt auch diesen Absatz früher auf derselben Seite:
Ihr Container-Ansichts-Controller muss sich einen untergeordneten Ansichts-Controller zuordnen, bevor Sie die Stammansicht des untergeordneten Elements zur Ansichtshierarchie hinzufügen. Auf diese Weise kann iOS Ereignisse ordnungsgemäß an untergeordnete Ansichtscontroller und die von diesen Controllern verwalteten Ansichten weiterleiten. Nachdem die Stammansicht eines Kindes aus seiner Ansichtshierarchie entfernt wurde, sollte der Controller für die untergeordnete Ansicht von sich selbst getrennt werden. Um diese Zuordnungen herzustellen oder zu lösen, ruft Ihr Container bestimmte Methoden auf, die von der Basisklasse definiert wurden. Diese Methoden sollen nicht von Clients Ihrer Containerklasse aufgerufen werden. Sie dürfen nur von der Implementierung Ihres Containers verwendet werden, um das erwartete Containment-Verhalten bereitzustellen.
Hier sind die wesentlichen Methoden, die Sie möglicherweise aufrufen müssen:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
Es gibt jedoch keinen Hinweis darauf, um welche "Ereignisse" oder "erwartetes Eindämmungsverhalten" es sich handelt oder warum (oder sogar wann) das Aufrufen dieser Methoden "wesentlich" ist.
Die Beispiele für benutzerdefinierte Container-Ansichts-Controller im Abschnitt "Benutzerdefinierte Container-Ansichts-Controller" der Apple-Dokumentation rufen alle diese Methode auf. Ich gehe daher davon aus, dass sie einen wichtigen Zweck erfüllt, der über das einfache Platzieren des untergeordneten ViewControllers in einem Array hinausgeht, aber ich kann nicht herausfinden heraus, was dieser Zweck ist. Was macht diese Methode und warum sollte ich sie aufrufen?
quelle
Antworten:
Ich habe mich auch über diese Frage gewundert. Ich habe mir Session 102 der WWDC 2011- Videos angesehen und Mr. View Controller, Bruce D. Nilo , sagte Folgendes:
Es scheint also, dass der Aufruf zu
addChildViewController:
sehr wenig bewirkt. Die Nebenwirkungen des Anrufs sind der wichtige Teil. Sie kommen aus denparentViewController
undchildViewControllers
Beziehungen. Hier sind einige der Nebenwirkungen, die ich kenne:transitionFromViewController:toViewController:…
wenn beide VCs dasselbe übergeordnete Element benötigennavigationController
,tabBarController
usw. Eigenschaftenquelle
Ich denke, ein Beispiel sagt mehr als tausend Worte.
Ich habe an einer Bibliotheks-App gearbeitet und wollte eine schöne Notizblockansicht anzeigen, die angezeigt wird, wenn der Benutzer eine Notiz hinzufügen möchte.
Nachdem ich einige Lösungen ausprobiert hatte, erfand ich schließlich meine eigene benutzerdefinierte Lösung, um den Notizblock anzuzeigen. Wenn ich also den
NotepadViewController
Editor anzeigen möchte, erstelle ich eine neue Instanz von und füge die Stammansicht als Unteransicht zur Hauptansicht hinzu. So weit, ist es gut.Dann bemerkte ich, dass das Notizblockbild im Querformat teilweise unter der Tastatur versteckt ist.
Also wollte ich das Notizblockbild ändern und es nach oben verschieben. Und dazu habe ich den richtigen Code in
willAnimateRotationToInterfaceOrientation:duration:
method geschrieben, aber als ich die App ausführte, passierte nichts! Und nach dem Debuggen bemerkte ich, dass keine derUIViewController
Rotationsmethoden tatsächlich aufgerufen wirdNotepadViewController
. Es werden nur die Methoden im Hauptansichts-Controller aufgerufen.Um dies zu lösen, musste ich alle Methoden
NotepadViewController
manuell aufrufen, wenn sie im Hauptansichts-Controller aufgerufen wurden. Dies wird die Dinge bald komplizieren und eine zusätzliche Abhängigkeit zwischen nicht verwandten Komponenten in der App schaffen.Das war in der Vergangenheit, bevor das Konzept der untergeordneten Ansichtssteuerungen eingeführt wurde. Jetzt müssen Sie nur noch
addChildViewController
den Hauptansichts-Controller aufrufen, und alles funktioniert wie erwartet ohne weitere manuelle Arbeit.Bearbeiten: Es gibt zwei Kategorien von Ereignissen, die an untergeordnete Ansichtscontroller weitergeleitet werden:
1- Erscheinungsmethoden:
2- Rotationsmethoden:
Sie können auch steuern, welche Ereigniskategorien Sie automatisch weiterleiten möchten, indem Sie
shouldAutomaticallyForwardRotationMethods
und überschreibenshouldAutomaticallyForwardAppearanceMethods
.quelle
addChildViewController
an den übergeordneten Controller weitergeleitet werden.-[UIViewController addChildViewController:]
Fügt nur den übergebenen View-Controller in ein Array von viewControllern ein, auf die ein viewController (das übergeordnete Element) verweisen möchte. Sie sollten die Ansichten von viewController tatsächlich selbst auf dem Bildschirm hinzufügen, indem Sie sie als Unteransichten einer anderen Ansicht hinzufügen (z. B. der Ansicht von parentViewController). In Interface Builder gibt es auch ein praktisches Objekt zur Verwendung von childrenViewControllern in Storyboards.Zuvor mussten Sie in @properties manuell auf diese viewController verweisen, deren Ansichten Sie verwendet haben. Eine integrierte Eigenschaft wie
childViewControllers
und folglichparentViewController
ist eine bequeme Möglichkeit, solche Interaktionen zu verwalten und zusammengesetzte viewController wie den UISplitViewController zu erstellen, den Sie auf iPad-Apps finden.Darüber hinaus empfangen childrenViewController automatisch alle Systemereignisse, die das übergeordnete Element empfängt: -viewWillAppear, -viewWillDisappear usw. Bisher sollten Sie diese Methoden auf Ihren "childrenViewControllern" manuell aufgerufen haben.
Das ist es.
quelle
iOS "system events"
wirft nicht viel auf. Es scheint kein Begriff zu sein, den Apple verwendet.