Jak działa View Controller Containment w iOS 5?

108

W WWDC 2011 Session 102, Apple wprowadził View Controller obudowy, która jest zdolność do tworzenia niestandardowego widoku pojemników kontrolera, analogicznie do UITabBarController, UINavigationControlleri tym podobne.

Kilka razy oglądałem przykłady. Istnieje wiele metod związanych z tym wzorcem, ale trochę trudno było je dokładnie rozgryźć. Zamierzam opublikować tutaj, co myślę, że się dzieje i zobaczę, czy społeczność potwierdzi lub zaprze moje podejrzenia.

Scenariusz 1: przejście od braku nadrzędnego do nowego nadrzędnego kontrolera widoku

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

Czy pierwsze dwie linie muszą występować w podanej kolejności, czy można je odwrócić?

Scenariusz 2: przejście z nadrzędnego kontrolera widoku na brak nadrzędnego kontrolera widoku

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

Czy trzeba też dzwonić [vc didMoveToParentViewController:nil]? Przykłady z sesji 102 nie zrobiły tego w tym scenariuszu, ale nie wiem, czy było to przeoczenie, czy nie.

Scenariusz 3: przejście z jednego nadrzędnego kontrolera widoku na inny

Prawdopodobnie nastąpi to w następujący sposób, ponieważ logika w każdym nadrzędnym kontrolerze widoku zostanie hermetyzowana.

// 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];

pytania

Moje główne pytanie brzmi: czy w ogóle tak powinno działać ograniczenie kontrolera widoku? Czy mechanika podana powyżej jest poprawna?

Czy willMoveToParentViewControllerprzed dzwonieniem trzeba zadzwonić addChildViewController? Wydaje mi się to logicznym porządkiem, ale czy jest to absolutnie konieczne?

Czy didMoveToParentViewController:nilpo dzwonieniu trzeba dzwonić removeFromParentViewController?

Gregory Higley
źródło

Odpowiedzi:

72

Dokumentacja UIViewControllerjest dość jasna, kiedy i kiedy nie wywoływać willMove/ didMoveMethods. Zapoznaj się z dokumentacją „Implementowanie kontrolera widoku kontenera” .

Doktorzy mówią, że jeśli nie nadpisujesz addChildViewController, nie musisz wywoływać willMoveToParentViewController:metody. Jednak musisz wywołać didMoveToParentViewController:metodę po zakończeniu przejścia. „Podobnie, za wywołanie willMoveToParentViewController:metody przed wywołaniem removeFromParentViewControllermetody odpowiada kontroler widoku kontenera . removeFromParentViewControllerMetoda wywołuje didMoveToParentViewController:metodę podrzędnego kontrolera widoku”.

Ponadto, nie jest przykładem wypracowane tutaj i przykładowy kod tutaj .

Powodzenia

timthetoolman
źródło
17
Rozumiem, więc addChildViewControllerpowinno być zrównoważone zdidMoveToParentViewController i willMoveToParentViewControllerpowinno być równoważone removeFromParentViewController. To jest dokładnie to, czego szukałem. Nie jestem pewien, jak przegapiłem to w dokumentach.
Gregory Higley,
Dlaczego nie? Dlaczego nie musisz wywoływać willMoveToParentViewController, ale musisz wywołać didMoveToParentViewController?
user4951
Ponieważ tak mówią doktorzy. Apple najwyraźniej czuje, że nie musimy o tym wiedzieć.
7
Powód jest ze względu na animację: załóżmy, że tworzysz własny kontroler nawigacyjny. Na początku animacji wsuwanej należy nazwać „willMove”, a na końcu animacji „didMove”. Teraz, gdy wywołasz „addChild” na początku animacji, automatycznie wywoła ona dla Ciebie „willMove”. Ale nie może wiedzieć, kiedy animacja (jeśli taka istnieje) się kończy, więc musisz ręcznie wywołać „didMove” na końcu animacji (lub natychmiast w przypadku braku animacji).
Chris
2
A jeśli chodzi o animację „wysuń”, np. Dziecko jest usuwane, musisz ręcznie wywołać „willMove” na początku animacji, ponieważ uikit w przeciwnym razie nie wiedziałby, kiedy wywołać funkcję „viewWillDisappear” Twojego dziecka. A na końcu animacji, gdy wywołasz removeFromParentViewController, może ona automatycznie wywołać „didMove”.
Chris,
23

Ta część jest nieprawidłowa:

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

Według dokumentów:

Gdy kontener niestandardowy wywołuje metodę addChildViewController:, automatycznie wywołuje metodę willMoveToParentViewController: kontrolera widoku, która ma zostać dodana jako element podrzędny przed jej dodaniem.

Więc nie potrzebujesz [vc willMoveToParentViewController:self]telefonu. Odbywa się to automatycznie, gdy dzwonisz [self addChildViewController:vc]. Oto ponownie przykładowy kod:

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

Aby usunąć kontrolery widoku:

Metoda removeFromParentViewController automatycznie wywołuje metodę didMoveToParentViewController: kontrolera widoku podrzędnego po usunięciu elementu podrzędnego.

Prawdopodobnie to wezwanie [oldVC didMoveToParentViewController:nil].

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
// [vc didMoveToParentViewController:nil] called automatically
Nevan King
źródło
wygląda na to, że jeśli zrobiono inaczej, nawet jeśli wydaje się działać, PresentViewController nie jest ustawiony na PresentViewController.
Adrian
Dokumenty mówią call didMoveToParentViewControllernatychmiast po wywołaniu metody addChildViewController:”, ale nie określa, kiedy faktycznie dodajesz podwidok podrzędny. Zastanawiam się, czy wszyscy się mylili. Czy jest przykład w niektórych dokumentach Apple Docs, na podstawie których możemy to sprawdzić?
Robert
Uwaga: możesz zrobić potrzebę, aby zadzwonić willMoveToParentViewControllerprzed addChildViewControllerjeżeli rzecz poruszają to klasa zwyczaj z przesłonięte addChildViewController(chyba że przesłanianie nazywa ją wewnętrznie)
bunkerdive