Ostrzeżenie: odradza się prezentowanie kontrolerów widoku na odłączonych kontrolerach widoku

180

W mojej aplikacji korzystam z kontrolera nawigacyjnego. Później w pewnym widoku używam presentViewControllerdo wyświetlania powiększonego obrazu. Nie używam również Storyboard ani stalówki.

Ten błąd pojawia się tylko w systemie iOS 7. Działa dobrze w iOS 6 i wcześniejszych:

Prezentowanie kontrolerów widoku na odłączonych kontrolerach widoku jest odradzane

Gagan Joshi
źródło
Jeszcze się nie domyśliłem. Ale w mojej aplikacji nie przypisuję żadnego kontrolera widoku do kontrolera window.rootview. dodaję widok do okna. Być może to jest dla mnie powód. ale nie jestem pewien ...
Gagan Joshi
@GaganJoshi Przyczyna, o której wspomniałeś powyżej, może nie być przyczyną. Nawet ja mam ten sam problem. W naszym projekcie przypisuję kontroler widoku do kontrolera window.rootview.
Rajesh,
1
Myślę, że pozostałe komentarze poprawnie odnoszą się do czegoś na temat rootViewController i połączenia z oknem. Nie do końca to rozgryzłem, ale udało mi się obejść ten problem, prezentując kontroler bezpośrednio na rootViewController zamiast na kontrolerze nawigacyjnym lub jednym z jego dzieci.
Rich Waters

Odpowiedzi:

207

Aby uniknąć ostrzeżenia w nawigacji push, możesz bezpośrednio użyć:

[self.view.window.rootViewController presentViewController:viewController animated:YES completion:nil];

A potem w twoim modalnym kontrolerze widoku, kiedy wszystko jest skończone, możesz po prostu wywołać:

[self dismissViewControllerAnimated:YES completion:nil];

cdescours
źródło
Prezentuję próbnik obrazu z tym kodem wiersza „[self.view.window.rootViewController presentViewController: viewController animowany: TAK zakończenie: zero];” Ale nie można odrzucić widoku poicker za pomocą tego wiersza „[selfISSissViewControllerAnimated: TAK ukończenie: zero];” Każda alternatywna opcja dla kontrolera
komisarza
@keyurbhalodiya Aby wywołać działanie, należy wywołać metodę dismissViewController z modalView. Więc jeśli wyświetliłeś widok o nazwie viewB z widoku A z [viewA.window.rootViewController presentViewController: viewB], w viewB musisz dodać przycisk, na przykład powiązany z niestandardową akcją wywołującą [selfclissViewControllerAnimated]. Czy to jest jaśniejsze?
cdescours
11
Brak prezentacji kontrolera widoku w iOS 8.
Rajesh Maurya
1
dla iOS 8: [self.view.window.rootViewController.navigationController
Fede Cugliandolo
31
za pomocą self.navigationControllerzrobił to dla mnie.
Brandon Zacharie
62

Powodem tego ostrzeżenia jest to, że przedstawiałem kontroler widoku w małym widoku, który nie jest widokiem w pełnym rozmiarze. Poniżej znajduje się obraz mojego projektu. gdzie po kliknięciu na cztery opcje powyżej. Użytkownik nawiguje do innego widoku kontrolera dzieci (działa jak tabViewcontroller). Ale kontroler widoku dziecka zawiera widok małego rozmiaru. Więc jeśli przedstawimy widok z kontrolera podglądu dziecka, wyświetli to ostrzeżenie.

główny widok szczegółów

Aby tego uniknąć, możesz przedstawić pogląd na rodzica kontrolującego dziecko

  [self.parentViewController presentViewController:viewController animated:YES completion:nil];
Gagan Joshi
źródło
1
[self.view.window.rootViewController.navigationController pushViewController: YOUR_VIEW_CONTROLER animowany: TAK];
Fede Cugliandolo,
1
„przedstawiał kontroler widoku na małym widoku, który nie jest widokiem w pełnym rozmiarze”. ... DOKŁADNIE. Dobra robota.
Fattie
61

Poczekaj na viewDidAppear():

Ten błąd może również wystąpić, jeśli próbujesz przedstawić kontroler widoku, zanim widok faktycznie się pojawił, na przykład prezentując widok w viewWillAppear()lub wcześniej. Spróbuj przedstawić inny widok po nim viewDidAppear()lub wewnątrz niego.

Azaksja
źródło
9
Innymi słowy, nie prezentuj żadnych kontrolerów widoku viewDidLoad(), ludzie! Popełniłem ten błąd wiele razy ...
T Blank
Dzięki temu pomogłem. Miałem kod w viewDidLoad, gdzie próbował wyświetlić okno dialogowe na końcu.
ArdenDev,
Ten błąd pojawia się podczas uruchamiania testów jednostkowych / integracyjnych, w których nie testuję animacji.
mixtly87,
21

W moim przypadku mam sampleViewControllerwidok dodany jako widok podrzędny, a następnie próbuję przedstawić popover z widoku sampleViewController(tutaj selfzamiast UIViewControllerinstancji):

[self.view addSubview:sampleViewController.view];

Właściwa droga powinna być poniżej:

// make sure the vc has been added as a child view controller as well
[self addChildViewController:sampleViewController];
[self.view addSubview:sampleViewController.view];
[sampleViewController didMoveToParentViewController:self];

Btw, działa to również w przypadku, który przedstawia popover z komórki widoku tabeli, wystarczy upewnić się, że kontroler widoku tabeli został również dodany jako kontroler widoku potomnego.

Kjuly
źródło
Ponadto wywołanie didMoveToParentViewController. Zarzuty sprawdź Dodaj i usuń ChildViewController: gist.github.com/tomohisa/2897676
Jakehao
@jianzong pamiętam, że nie trzeba robić ostatniego kroku. W każdym razie pozwólcie, że dodam to, dzięki za sugestię. :)
Kwietnia
Tak, zadziała bez ostatniego kroku. Myślę, że celem tego jest poinformowanie parentViewController, aby wywołał pewne metody, aby coś zrobić. :)
Jakehao,
2
działa dla mnie, używam widoku jednego kontrolera w innym kontrolerze - (programowo widok kontenera), nie [self addChildViewController:sampleViewController];dodałem, teraz dodałem to, dziękuję
anjnkmr
16

Myślę, że problem polega na tym, że nie masz odpowiedniej hierarchii kontrolera widoku. Ustaw kontroler rootview aplikacji, a następnie pokaż nowe widoki, wypychając lub prezentując na nich nowe kontrolery widoków. Pozwól każdemu kontrolerowi widoku zarządzać swoimi widokami. Tylko kontrolery widoków kontenerów, takie jak kontroler tabbarview, powinny dodawać widoki innych kontrolerów widoków do swoich własnych widoków. Przeczytaj przewodnik programowania kontrolerów widoku, aby dowiedzieć się więcej na temat prawidłowego korzystania z kontrolerów widoku. https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/

Daniel Ytterbrink
źródło
14

Szybki 3

Dla każdego, kto się na to natknie, oto szybka odpowiedź.

self.parent?.present(viewController, animated: true, completion: nil)
Jeremie
źródło
9

Mam prawie ten sam problem. Powodem było to, że próbowałem przedstawić „jakiś” kontroler na innym, a po zakończeniu animacji ustawiałem prezentowany kontroler jako root. Po tej operacji wszystkie kolejne kontrolery prezentujące przynoszą mi ostrzeżenie: „Nie zaleca się prezentowania kontrolerów widoku na odłączonych kontrolerach widoku ”. I rozwiązuję to ostrzeżenie, ustawiając „niektóre” kontrolery jako root bez żadnej prezentacji na początku.

Oddalony:

[[self rootController] presentViewController:controller animated:YES completion:^{

       [self window].rootViewController = controller;

       [[self window] makeKeyAndVisible];}];

Po prostu zrób jako root bez żadnej prezentacji:

 [[self window] setRootViewController:controller];
averem
źródło
1
To był dokładnie mój problem. Próbowałem przedstawić go za pomocą UIModalTransitionStyleCrossDissolve, a następnie uczynić go rootViewController. Następnie wszystkie inne prezentacje zakończyły się niepowodzeniem przy podanym komunikacie ostrzegawczym. Wystarczyło ustawić go jako rootViewcontroller bez animacji. Dzięki!
Bernardo Oliveira,
7

Jednym z rozwiązań tego problemu jest posiadanie kontrolera podglądu dziecka. Po prostu prezentujesz kontroler podglądu na jego rodzicu przez dany

[self.parentViewController presentViewController:viewController animated:YES completion:nil];

Do zwolnienia użyj tego samego kontrolera odrzucania.

[self dismissViewControllerAnimated:YES completion:nil];

To idealne rozwiązanie działa dla mnie.

Gagan Joshi
źródło
7

Użyj [self.navigationController presentViewController:xxx animated:YES completion:nil]w iOS 8.

Tao Fang
źródło
5

Wypróbuj ten kod

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:<your ViewController object>];

[self.view.window.rootViewController presentViewController:navigationController animated:YES completion:nil];
Vlad
źródło
4

Spróbuj przedstawić, TabBarControllerjeśli jest to TabBarControlleraplikacja oparta.

[self.tabBarController presentViewController:viewController animated:YES completion:nil];

Przyczyną może być selfdziecko, TabBarControllera ty próbujesz przedstawić coś od ChildViewController.

Warif Akhand Rishi
źródło
4

Tak, napotkałem również ten sam komunikat ostrzegawczy podczas wyświetlania kontrolera alertów, który był w innym widoku. Później uniknąłem tego, prezentując kontroler alertów z kontrolera widoku nadrzędnego, jak poniżej:

[self.parentViewController presentViewController:alertController animated:YES completion:nil];
Sivasagar Palakurthy
źródło
3

musisz dodać kontroler widoku, który będzie prezentował nowy kontroler jako dziecko nadrzędnego kontrolera widoku.

Załóżmy, że masz swój główny kontroler, a następnie dodajesz nowy kontroler o nazwie kontroler A, a następnie chcesz przedstawić nowy kontroler o nazwie kontroler B z kontrolera A

musisz napisać coś takiego:

[self addChildViewController:controllerA]; //self is yourMainViewController
[self.view addsubView:controllerA.view]; 

oraz w kontrolerze A możesz przedstawić nowego kontrolera bez ostrzeżeń

[self presentViewController:controllerB animated:YES completion:nil]; //self is controllerA
Chuy47
źródło
3

W Swift 4.1 i Xcode 9.4.1

Rozwiązaniem jest

DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})

Jeśli piszesz w ten sposób, otrzymuję ten sam błąd

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
    })
alert.addAction(defaultAction)

present(alert, animated: true, completion: nil) 

Otrzymuję ten sam błąd

Presenting view controllers on detached view controllers is discouraged <MyAppName.ViewController: 0x7fa95560Z070>.

Kompletne rozwiązanie to

let alert = UIAlertController(title: "title", message: "message", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
     })
alert.addAction(defaultAction)
//Made Changes here    
DispatchQueue.main.async(execute: {
    self.present(alert, animated: true)
})
iOS
źródło
Uruchomienie go przez DispatchQueue w ten sposób działało dla mnie. Robię performSegue do modalnego kontrolera widoku, wywoływanego z viewDidLoad na moim pierwszym kontrolerze widoku (ekran wprowadzający pierwszego uruchomienia, aby zorientować nowych użytkowników). Ładowało się dobrze, ale generowało ostrzeżenie. Zawijanie wywołania performSegue w wywołaniu asynchronicznym DispatchQueue eliminuje ostrzeżenie. Dzięki!
Grant Neufeld
1

Upewnij się, że masz kontroler widoku głównego na początek. Możesz to ustawić didFinishLaunchingWithOptions.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [window setRootViewController:viewController];
}
samwize
źródło
1

Wiele powodów tego ostrzeżenia. Mój jest, ponieważ mam segment połączony z ViewController do innego, który będzie prezentowany modalnie. Ale ViewController, z którego prezentuję, jest generowany dynamicznie przez PageViewController. Dlatego jest odłączony w serii ujęć. Moja aplikacja nie ulegnie awarii z tego powodu; ale chciałbym uciszyć ostrzeżenie.

Lee Probert
źródło
1

Dotarłem do tego wątku, w którym mam niestandardowy pasek nawigacji i przez niego dzwoniłem do AlertViewController.

Musiałem dodać go jako dziecko do mojego głównego kontrolera widoku. Wtedy mógłbym zadzwonić, przedstawić to bez żadnego ostrzeżenia.

Powinieneś dodać swoją Zoomed Image View Controllerjako dziecko głównego ViewController.

(na przykład)

[self addChildViewController:ZoomedImageViewController];

Wtedy możesz zadzwonić do swojego ZoomedImageViewController

[self presentViewController:ZoomedImageViewController];
Naveed Abbas
źródło
1

Wiele odpowiedzi jest poprawnych.

  • Sprawdź, czy Twój prezentacjiViewController ma ParentViewController, czy nie.
  • Jeśli nie, dodaj go gdzieś, gdzie powinien zostać dodany
  • w przeciwnym razie sprawdź, czy to parentViewController ma rekursywnie parentViewController, dopóki każdy viewController nie będzie nadrzędny

Ten problem przytrafił mi się, gdy mój współpracownik dodał AViewController do BViewController. W jakiś sposób po prostu dodał widok AViewController do widoku BViewController.

Naprawiono przez dodanie bViewController.addChild (aViewController)

Jerome Li
źródło
1
Dziękuję Ci! dodanie addChild w moim bloku ukończenia przejścia Hero.shared.transition całkowicie rozwiązało mój problem.
landnbloc
0

To zależy, czy chcesz pokazać swój alert lub coś podobnego w jakimkolwiek rodzaju UIViewController.

Możesz użyć tego przykładu kodu:

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"Example" preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault handler:nil];

[alert addAction:cancelAction];


[[[[[UIApplication sharedApplication] delegate] window] rootViewController] presentViewController:alert animated:true completion:nil];
Fabio
źródło
Twój kod nie działa i wyświetla ten dziennikAttempt to present <UIAlertController: 0x7fc01a1eb600> on <ViewController: 0x7fc019821e00> whose view is not in the window hierarchy!
Naveed Abbas,