rozważ następujący scenariusz: Mam aplikację opartą na scenorysach. Dodaję obiekt ViewController do scenorysu, dodaję pliki klas dla tego ViewController do projektu i określam nazwę nowej klasy w inspektorze tożsamości IB. Jak mam zamiar programowo odwoływać się do tego ViewController z AppDelegate? Utworzyłem zmienną z odpowiednią klasą i przekształciłem ją we właściwość IBOutlet, ale nie widzę żadnego sposobu, aby móc odwoływać się do nowego ViewController w kodzie - żadna próba przeciągnięcia połączenia przy użyciu klawisza Ctrl nie działa .
tj. w ramach AppDelegate mogę dostać się do podstawowego ViewController w ten sposób
(MyViewController*) self.window.rootViewController
ale co z każdym innym ViewController zawartym w serii ujęć?
iphone
objective-c
ios
uiviewcontroller
storyboard
Matthias D.
źródło
źródło
Odpowiedzi:
Zapoznaj się z dokumentacją dotyczącą
-[UIStoryboard instantiateViewControllerWithIdentifier:]
. Pozwala to na utworzenie instancji kontrolera widoku ze scenorysu przy użyciu identyfikatora ustawionego w Inspektorze atrybutów IB:EDYTOWANO, aby dodać przykładowy kod:
źródło
[[[self window] rootViewController] storyboard]
Zgodnie z dokumentami zwróci to „scenorys, z którego pochodzi kontroler widoku”. (lub zero, jeśli nie pochodzi ze scenorysu). Z tej tablicy UIStoryboard * możesz użyć wywołań instancji, o których wspomniał @RobinSummerhill. Zauważ, że Storyboardy tworzą nowe wystąpienia twoich viewControllers ( scen ), gdy są potrzebne, i nie używają ponownie tych, które były wcześniej przeglądane.Jeśli używasz
XCode
5, powinieneś to zrobić w inny sposób.UIViewController
wUIStoryboard
Identity Inspector
prawego górnego okienkaUse Storyboard ID
wyboruStoryboard ID
poluNastępnie napisz swój kod.
źródło
Ogólnie system powinien obsługiwać tworzenie instancji kontrolera widoku z scenorysem. To, czego chcesz, to przechodzenie przez hierarchię viewController, przechwytując odwołanie do
self.window.rootViewController
kontrolerów widoku, w przeciwieństwie do inicjowania kontrolerów widoku, które powinny być już poprawnie zainicjowane, jeśli poprawnie skonfigurowałeś scenorys.Powiedzmy, że
rootViewController
jest to kontroler UINavigationController, a następnie chcesz wysłać coś do kontrolera widoku z góry, zrobiłbyś to w następujący sposób w AppDelegatedidFinishLaunchingWithOptions
:W Swift, jeśli byłoby bardzo podobne:
Naprawdę nie powinieneś inicjować kontrolerów widoku przy użyciu identyfikatorów scenorysu od delegata aplikacji, chyba że chcesz ominąć normalny sposób ładowania scenorysu i samodzielnie załadować całą scenorys. Jeśli musisz zainicjować sceny z AppDelegate, najprawdopodobniej robisz coś nie tak. Chodzi mi o to, że wyobraź sobie, że z jakiegoś powodu chcesz wysłać dane do kontrolera widoku w dół stosu, AppDelegate nie powinien sięgać daleko do stosu kontrolera widoku, aby ustawić dane. To nie jego sprawa. To biznes to rootViewController. Pozwól, aby rootViewController obsługiwał własne elementy podrzędne! Tak więc, gdybym ominął normalny proces ładowania scenorysu przez system, usuwając odniesienia do niego w pliku info.plist, co najwyżej utworzyłbym instancję rootViewController za pomocą
instantiateViewControllerWithIdentifier:
i prawdopodobnie jego katalog główny, jeśli jest to kontener, taki jak UINavigationController. To, czego chcesz uniknąć, to tworzenie wystąpień kontrolerów widoku, które zostały już utworzone przez scenorys. To jest problem, który widzę często. Krótko mówiąc, nie zgadzam się z zaakceptowaną odpowiedzią. Jest to niepoprawne, chyba że plakaty oznaczają usunięcie ładowania storyboardu z info.plist, ponieważ w przeciwnym razie załadujesz 2 storyboardy, co nie ma sensu. Prawdopodobnie nie jest to wyciek pamięci, ponieważ system zainicjował scenę główną i przypisał ją do okna, ale potem przyszedłeś, ponownie utworzyłeś instancję i przypisałeś ją ponownie. Twoja aplikacja ma zły start!źródło
źródło