2013-06-19 10 views
83

Ich tauche meine Füße zum ersten Mal in die iOS-Entwicklung, und eines der ersten Dinge, die ich tun musste, ist eine custom container view controller - nennen wir es SideBarViewController - die austauscht, welche von mehreren möglichen Kind-View-Controller es zeigt, fast genau wie ein Standard Tab Bar Controller. (Es ist so ziemlich ein Tab Bar-Controller aber mit einem ausblendbar Seite Menü statt einer Tab-Leiste.)Was macht addChildViewController eigentlich?

gemäß den Anweisungen in der Apple-Dokumentation, ich addChildViewController rufen, wenn ich ein Kind Viewcontroller zu meinem Container hinzufügen. Mein Code zum Austausch der aktuellen Kind-View-Controller aus der SideBarViewController gezeigt wird, sieht wie folgt 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 begann ich versuche nur, um herauszufinden, was addChildViewController hier der Fall ist, und ich erkannte, dass ich keine Ahnung habe. Abgesehen davon, dass das neue ViewController im Array .childViewControllers steckt, scheint es nichts zu bewirken. Aktionen und Ausgänge von der Ansicht des Kind-Controllers zu dem Kind-Controller, die ich auf dem Storyboard eingestellt habe, funktionieren immer noch gut, auch wenn ich nie addChildViewController aufrufen, und ich kann mir nicht vorstellen, was es sonst beeinflussen könnte. Tatsächlich

, wenn ich meinen Code neu schreiben, um nicht addChildViewController zu nennen, und stattdessen wie folgt aussehen ...

- (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 meine app funktioniert immer noch einwandfrei, soweit ich das sagen kann!

Die Apple-Dokumentation wirft nicht viel Licht auf was addChildViewController tut, oder warum wir es nennen sollen. Das gesamte Ausmaß der jeweiligen Beschreibung dessen, was die Methode tut oder warum sollte es im UIViewController Class Reference in seinem Abschnitt verwendet werden, derzeit:

Fügt die angegebene View-Controller als Kind. ... Diese Methode soll nur von einer Implementierung eines benutzerdefinierten Containeransicht-Controllers aufgerufen werden. Wenn Sie diese Methode überschreiben, müssen Sie super in Ihrer Implementierung aufrufen.

Es gibt auch diesen Absatz früher auf der gleichen Seite:

Ihre Container-View-Controller ein Kind View-Controller mit mir selbst vor dem Hinzufügen des Kindes Root-Ansicht zu der Ansicht Hierarchie zuordnen müssen. Dadurch kann iOS Ereignisse ordnungsgemäß an untergeordnete Ansichtscontroller und die Ansichten, die diese Controller verwalten, weiterleiten. Nachdem es die Stammansicht eines untergeordneten Elements aus seiner Ansichtshierarchie entfernt hat, sollte es den untergeordneten Ansichtscontroller ebenfalls von sich selbst trennen. Um diese Zuordnungen zu erstellen oder zu brechen, ruft Ihr Container bestimmte Methoden auf, die von der Basisklasse definiert werden. 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 nennen können müssen:

addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:

aber es bietet keine Ahnung, was die "Ereignisse" oder "erwartetes Eindämmungsverhalten", von denen gesprochen wird, oder warum (oder sogar wann) diese Methoden aufgerufen werden, ist "wesentlich". Die Beispiele von benutzerdefinierten Containeransichtscontrollern im Abschnitt "Benutzerdefinierte Containeransichtscontroller" der Apple-Dokumentation rufen alle diese Methode auf. Daher nehme ich an, dass sie einen wichtigen Zweck erfüllt, nicht nur den untergeordneten ViewController auf ein Array zu setzen, sondern auch I kann nicht herausfinden, was dieser Zweck ist. Was macht diese Methode und warum sollte ich sie nennen?

+3

Apples [** 2011 WWDC **] (https://developer.apple.com/videos/wwdc/2011/) Die Videoseite enthält eine große Sitzung ("Implementieren von UIViewController Containment") zu diesem Thema. – Alladinian

Antwort

81

Ich fragte mich auch über diese Frage. Ich sah Session 102 of the WWDC 2011 Videos und Herr-View-Controller, Bruce D. Nilo, sagte dieser:

viewWillAppear:, viewDidAppear:, etc nichts mit addChildViewController: zu tun haben. All das addChildViewController: ist zu sagen "Dieser View-Controller ist ein Kind von diesem" und es hat nichts mit Aussehen der Ansicht zu tun. Wenn sie aufgerufen werden, werden sie zugeordnet, wenn Ansichten in die Fensterhierarchie ein- und ausgelagert werden.

So scheint es, dass der Anruf zu addChildViewController: sehr wenig tut. Die Nebenwirkungen des Anrufs sind der wichtige Teil. Sie kommen aus den parentViewController und childViewControllers Beziehungen. Hier sind einige der Nebenwirkungen, die ich kenne:

  • Forwarding Aussehen Methoden Kind Ansicht-Controller
  • Forwarding Rotationsverfahren
  • (möglicherweise) Weiterleitungsspeicher Warnungen
  • inkonsistent VC Hierarchien vermeiden, vor allem in transitionFromViewController:toViewController:… wobei beide VCs das gleiche übergeordnete Element haben müssen
  • Zulassen, dass benutzerdefinierte Container-View-Controller an der State Preservation and Restoration teilnehmen
  • T nter Teil in der Responder-Kette
  • Einhaken der navigationController, tabBarController, etc Eigenschaften
+0

Es ist Sitzung 102 nicht 101 – SeanChense

+0

+1 für die Responder-Kette. addChildViewController ist erforderlich, wenn Sie Touch-Ereignisse in einer Unteransicht eines untergeordneten UIViewControllers erhalten möchten – charlieb

9

-[UIViewController addChildViewController:] fügt nur den übergebenen View-Controller in einem Array von viewControllern hinzu, das ein viewController (das übergeordnete Element) den Verweis beibehalten möchte. Sie sollten die ViewController-Ansichten tatsächlich auf dem Bildschirm hinzufügen, indem Sie sie als Unteransichten einer anderen Ansicht hinzufügen (z. B. die Sicht des parentViewControllers). Es gibt auch ein Convenience-Objekt in Interface Builder, um ChildrenViewControllers in Storyboards zu verwenden.

Um Referenzen anderer ViewControllers, von denen Sie die Ansichten verwendet haben, zu behalten, mussten Sie manuell in @properties auf sie verweisen. Eine eingebaute Eigenschaft wie childViewControllers und folglich parentViewController 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 erhält childrenViewControllers automatisch auch alle Systemereignisse, die der Parent empfängt: -viewWillAppear, -viewWillDisappear, etc. Zuvor sollten Sie diese Methoden manuell auf Ihren "childrenViewControllern" aufgerufen haben.

Das ist es.

+0

Was ist Ihre Grundlage für das Denken, dass es das ist? Können Sie auch eine Liste der Systemereignisse angeben, die vom Kind empfangen werden? Eine Google-Suche nach "iOS" -Systemereignissen "wirft nicht viel auf; Es scheint kein Begriff zu sein, den Apple benutzt. –

+0

Es handelt sich im Grunde genommen um eine bequeme Methode, mit der Sie die Ansicht von View Controller B als Unteransicht von View Controller A hinzufügen können, die Ansicht von Controller B jedoch immer noch verwalten kann. Damit dies ordnungsgemäß funktioniert, müssen Sie sicherstellen, dass View Controller B die Systemereignisse erhält (lesen Sie die Rückrufe von UIViewControllerDelegate). 'addChildViewController' führt dies für Sie durch, um Ihnen die Mühe zu ersparen, alles manuell zu übergeben. –

94

Ich denke, ein Beispiel sagt mehr als tausend Worte.

Ich arbeitete an einer Bibliothek App und wollte eine nette Notizblockansicht anzeigen, die angezeigt wird, wenn der Benutzer eine Notiz hinzufügen möchte.

enter image description here

Nach einigen Lösungen versucht, beenden ich meine eigene benutzerdefinierte Lösung zu erfinden, um die Notizen zu zeigen. Wenn ich also den Notizblock anzeigen möchte, erstelle ich eine neue Instanz von NotepadViewController und füge seine Stammansicht als Unteransicht der Hauptansicht hinzu. So weit, ist es gut.

Dann habe ich festgestellt, dass das Editorbild im Querformat teilweise unter der Tastatur versteckt ist.

enter image description here

Also wollte ich den Notizblock ändern und verschieben nach oben. Und um dies zu tun, schrieb ich den richtigen Code in willAnimateRotationToInterfaceOrientation:duration: Methode, aber wenn ich die App lief nichts passiert ist! Und nach dem Debugging habe ich bemerkt, dass keine der UIViewController Rotationsmethoden tatsächlich in NotepadViewController aufgerufen wird. Nur die Methoden im Hauptansicht-Controller werden aufgerufen.

Um dies zu lösen, musste ich alle Methoden von NotepadViewController manuell aufrufen, wenn sie im Hauptansicht-Controller aufgerufen werden. 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 Kind-View-Controller eingeführt wird. Aber jetzt müssen Sie nur noch addChildViewController an den Hauptansicht-Controller und alles funktioniert wie erwartet ohne weitere manuelle Arbeit.

Edit: Es gibt zwei Kategorien von Ereignissen, die zu Kindern View-Controller weitergeleitet werden:

1- Aussehen Methoden:

- viewWillAppear: 
- viewDidAppear: 
- viewWillDisappear: 
- viewDidDisappear: 

2- Rotation Methoden:

- willRotateToInterfaceOrientation:duration: 
- willAnimateRotationToInterfaceOrientation:duration: 
- didRotateFromInterfaceOrientation: 

Sie können auch steuern, welche Ereigniskategorien automatisch weitergeleitet werden sollen, indem Sieüberschreibenund shouldAutomaticallyForwardAppearanceMethods.

+0

Aus der Dokumentation und nach einem kurzen Test glaube ich nicht, dass es ein anderes Ereignis gibt, das nur weitergeleitet wird, wenn Sie den übergeordneten Controller 'addChildViewController' hinzufügen. – Hejazi

+0

wünschen es automatisch weitergeleitet viewWillLayoutSubviews – MobileMon

Verwandte Themen