Próba prezentacji UIViewController na UIViewController, którego widok nie znajduje się w hierarchii okien

599

Właśnie zacząłem używać Xcode 4.5 i dostałem ten błąd w konsoli:

Ostrzeżenie: Próba zaprezentowania <finishViewController: 0x1e56e0a0> na <ViewController: 0x1ec3e000>, którego widoku nie ma w hierarchii okien!

Widok jest nadal prezentowany i wszystko w aplikacji działa dobrze. Czy to coś nowego w iOS 6?

Oto kod, którego używam do zmiany między widokami:

UIStoryboard *storyboard = self.storyboard;
finishViewController *finished = 
[storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];

[self presentViewController:finished animated:NO completion:NULL];
Kyle Goslan
źródło
3
Mam dokładnie ten sam problem, z wyjątkiem próby połączenia presentViewController:animated:completionsię z kontrolerem nawigacyjnym. Czy robisz to w delegacie aplikacji?
Tarnfeld,
Nie, robię to od jednego kontrolera widoku do drugiego. Znalazłeś jakieś rozwiązania?
Kyle Goslan,
Ten sam problem z częścią kodu, która zawsze działała przed użyciem Xcode 4.5, prezentuję UINavigationController, ale znowu to zawsze działało wcześniej.
Emanuele Fumagalli,
Mam ten sam problem, nie rozwiązany. Robi to od delegata aplikacji, a kontroler rootview dzwoniący „presentViewController” będący modułem UITabBarController.
darksider
3
również, jeśli wywołujesz tę metodę przed wywołaniem makeKeyAndVisible, przenieś ją później
mike_haney 18.12.12

Odpowiedzi:

1296

Skąd wywołujesz tę metodę? Wystąpił problem viewDidLoadpolegający na tym, że próbowałem przedstawić kontroler widoku modalnego w ramach metody. Rozwiązaniem było przeniesienie tego wywołania na viewDidAppear:metodę.

Zakładam, że widok kontrolera widoku nie znajduje się w hierarchii widoku okna w miejscu, w którym został załadowany (kiedy viewDidLoadwiadomość jest wysyłana), ale znajduje się w hierarchii okna po jej przedstawieniu (kiedy viewDidAppear:wiadomość jest wysyłana) .


Uwaga

Jeśli nie nawiązać połączenie presentViewController:animated:completion:w viewDidAppear:może napotkasz problem przy czym modalne kontroler widoku jest zawsze przedstawiony ilekroć pojawia się widok kontrolera widoku (która ma sens!) I tak modalna kontroler widoku prezentowane nigdy nie odejdzie .. .

Być może nie jest to najlepsze miejsce do prezentacji modalnego kontrolera widoku, a może konieczne jest zachowanie dodatkowego stanu, który pozwala prezentującemu kontrolerowi widoku zdecydować, czy powinien natychmiast przedstawić modalny kontroler widoku.

James Bedford
źródło
6
@James masz rację, widok najwyraźniej nie jest w hierarchii aż po viewWillAppear został rozwiązany i raz viewDidAppear została wywołana. Gdyby to było moje pytanie, zaakceptowałbym tę odpowiedź;)
Matt Mc
6
@james Thanks. Korzystanie z ViewDidAppear również rozwiązało problem. Ma sens.
Ali,
44
Chciałbym móc to zagłosować dwa razy. Właśnie miałem ten problem i doszedłem do tematu, aby przekonać się, że głosowałem już za ostatnim razem, gdy to widziałem.
Schrockwell,
7
Zauważ, że zmiana VC w viewDidAppear powoduje wykonanie segue z Animacją. Powoduje błysk / wyświetlanie tła.
Vincent
2
Tak, sztuczka polega na animacji viewWillAppear: (BOOL), ponieważ jest poprawna. Jeszcze jedna ważna rzecz, którą musisz wywołać w metodzie super, jako [super viewDidAppear: animated]; bez tego nie działa.
BootMaker
66

Inna potencjalna przyczyna:

Miałem ten problem, gdy przypadkowo dwukrotnie prezentowałem ten sam kontroler widoku. (Raz performSegueWithIdentifer:sender:wywołano go po naciśnięciu przycisku, a drugi raz z segue podłączonym bezpośrednio do przycisku).

Skutecznie dwa segu strzelały jednocześnie i dostałem błąd: Attempt to present X on Y whose view is not in the window hierarchy!

Chris Nolet
źródło
4
Miałem ten sam błąd, a twoja odpowiedź tutaj pomogła mi zorientować się, co się dzieje, to rzeczywiście ten błąd, naprawiony przez ciebie, proszę pana, dziękuję, +1
samouray
1
Usunąłem stary segue i podłączyłem VC do VC. Czy istnieje sposób na połączenie przycisku z StoryBoard z VC, ponieważ w ten sposób ciągle mnie popełniają błędy?
MCB,
Miałem ten sam błąd, Twoja odpowiedź rozwiązała mój problem, dziękuję za uwagę. Z poważaniem.
iamburak
1
lol, przez przypadek również tworzyłem dwa vc: z przycisku i performSegue, dzięki za podpowiedź !!!
Borzh
1
W moim przypadku dzwoniłem present(viewController, animated: true, completion: nil)w pętli.
Samo
38

viewWillLayoutSubviewsi viewDidLayoutSubviews(iOS 5.0+) można w tym celu wykorzystać. Są wywoływane wcześniej niż viewDidAppear.

Jonny
źródło
3
Mimo to są one używane także przy innych okazjach, więc myślę, że można je nazwać kilkakrotnie w ciągu „życia” widoku.
Jonny
Nie do tego też służą metody - jak sama nazwa wskazuje. viewDidAppear jest poprawny. Dobrym pomysłem jest czytanie cyklu życia widoku.
tooluser
To najlepsze rozwiązanie. W moim przypadku prezentacja w viewDidAppear powoduje ułamek sekundy pokazania kontrolera widoku przed załadowaniem modalu, co jest niedopuszczalne.
TMilligan
Ta odpowiedź działała najlepiej dla mnie, gdy próbowałem wyświetlić alert. Alert nie wyświetla się, gdy umieszczam go w viewDidLoad i viewWillAppear.
uplearnedu.com
26

Aby wyświetlić dowolny widok podrzędny do widoku głównego, użyj następującego kodu

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];

Aby odrzucić widok podrzędny z widoku głównego, użyj następującego kodu

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];
abdul sathar
źródło
Pracowałem także dla mnie
Aziz Javed
17

Napotkałem również ten problem, gdy próbowałem przedstawić UIViewControllerw viewDidLoad. Odpowiedź Jamesa Bedforda zadziałała, ale moja aplikacja najpierw pokazywała tło przez 1 lub 2 sekundy.

Po kilku badaniach znalazłem sposób na rozwiązanie tego za pomocą addChildViewController.

- (void)viewDidLoad
{
    ...
    [self.view addSubview: navigationViewController.view];
    [self addChildViewController: navigationViewController];
    ...
}
niezadowolony
źródło
9
Myślę, że brakuje ci [navigationViewController didMoveToParentViewController: self]
foFox
2
Wypróbowałem twój kod, wraz z sugestią foFox, a kiedy idę go usunąć od jego rodzica, nie zniknie. Lololol. Nadal tkwi bez naprawy.
Logicsaurus Rex,
Działa w Swift3.1
Kang Byul
@sunkehappy powyżej dwóch linii do wykorzystania przed presentviewcontroller, ale jego awaria dlaczego?
Iyyappan Ravi
14

Prawdopodobnie, podobnie jak ja, masz zły korzeń viewController

Chcę wyświetlić ViewControllerw non-UIViewControllerkontekście,

Więc nie mogę użyć takiego kodu:

[self presentViewController:]

Tak więc otrzymuję UIViewController:

[[[[UIApplication sharedApplication] delegate] window] rootViewController]

Z jakiegoś powodu (błąd logiczny) rootViewControllerjest to coś innego niż oczekiwano (normalne UIViewController). Następnie naprawiam błąd, zastępując rootViewControllergo UINavigationController, i problem zniknął.

Sanbrother
źródło
8

TL; DR Możesz mieć tylko 1 rootViewController i jego najnowszą prezentację. Nie próbuj więc wyświetlać innego kontrolera widoku, gdy jest już przedstawiony kontroler, który nie został zwolniony.

Po przeprowadzeniu kilku własnych testów doszedłem do wniosku.

Jeśli masz rootViewController, który chcesz zaprezentować wszystko, możesz napotkać ten problem.

Oto mój kod rootController (otwarty jest mój skrót do prezentacji kontrolera widoku z katalogu głównego).

func open(controller:UIViewController)
{
    if (Context.ROOTWINDOW.rootViewController == nil)
    {
        Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
        Context.ROOTWINDOW.makeKeyAndVisible()
    }

    ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}

Jeśli wywołam open dwa razy z rzędu (niezależnie od upływu czasu), zadziała to dobrze przy pierwszym otwarciu, ale NIE przy drugim otwarciu. Druga otwarta próba spowoduje błąd powyżej.

Jeśli jednak zamknę ostatnio prezentowany widok, a następnie zadzwonię, otwórz, to zadziała dobrze, gdy ponownie wywołam open (na innym kontrolerze widoku).

func close(controller:UIViewController)
{
    ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}

Doszedłem do wniosku, że rootViewController tylko MOST-RECENT-CALL jest w widoku Hierarchia (nawet jeśli go nie odrzuciłeś ani nie usunąłeś). Próbowałem grać ze wszystkimi wywołaniami modułu ładującego (viewDidLoad, viewDidAppear i wykonywanie opóźnionych wywołań wysyłki) i odkryłem, że jedynym sposobem, w jaki mogę go uruchomić, jest WYŁĄCZNIE wywołanie obecne z najwyżej kontrolera widoku.

Agresor
źródło
Wydaje się, że jest to o wiele bardziej powszechny problem, niż w wielu odpowiedziach, które głosowały na twoje. Niestety, było to niezwykle pomocne
rayepps
tak, wszystko dobrze i dobrze, ale jakie jest rozwiązanie ... mam wątek roboczy działający w tle, przechodzący do serwera i wyświetlający scenorysy po lewej i na środku, a cała metodologia jest nieprawdziwa .. to okropne .. to, co powinno być bryzą, jest całkowicie żart, bo al chcę to zrobić Wątek w tle to: wait wait decide push screen to fronti NIEMOŻLIWE jest IOS ????
Heelis
5

Mój problem polegał na tym, że przeprowadzałem metodę segue in UIApplicationDelegate, didFinishLaunchingWithOptionszanim zadzwoniłem makeKeyAndVisible()do okna.

Adam Johns
źródło
w jaki sposób? czy możesz rozwinąć? mam do czynienia z tym samym problemem. to jest mój kod niech initialViewControlleripad: UIViewController = mainStoryboardIpad.instantiateViewController (withIdentifier: "SplashController") jako UIViewController self.window .rootViewController = initialViewControlleripad self.window .makeKeyAndVisible ()?
shahtaj Khalid
4

W mojej sytuacji nie byłem w stanie postawić mojego w zastępstwie klasowym. Oto co mam:

let viewController = self // I had viewController passed in as a function,
                          // but otherwise you can do this


// Present the view controller
let currentViewController = UIApplication.shared.keyWindow?.rootViewController
currentViewController?.dismiss(animated: true, completion: nil)

if viewController.presentedViewController == nil {
    currentViewController?.present(alert, animated: true, completion: nil)
} else {
    viewController.present(alert, animated: true, completion: nil)
}
George_E
źródło
3

Miałem ten sam problem. Musiałem osadzić kontroler nawigacyjny i przedstawić go za jego pośrednictwem. Poniżej znajduje się przykładowy kod.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIImagePickerController *cameraView = [[UIImagePickerController alloc]init];
    [cameraView setSourceType:UIImagePickerControllerSourceTypeCamera];
    [cameraView setShowsCameraControls:NO];

    UIView *cameraOverlay = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 768, 1024)];
    UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"someImage"]];
    [imageView setFrame:CGRectMake(0, 0, 768, 1024)];
    [cameraOverlay addSubview:imageView];

    [cameraView setCameraOverlayView:imageView];

    [self.navigationController presentViewController:cameraView animated:NO completion:nil];
//    [self presentViewController:cameraView animated:NO completion:nil]; //this will cause view is not in the window hierarchy error

}
spoczynkowy
źródło
3

Jeśli masz obiekt AVPlayer z odtwarzanym wideo, musisz najpierw zatrzymać wideo.

Vlad
źródło
Mam na myśli, że wideo powinno zostać najpierw zatrzymane / wstrzymane.
Vlad
właściwie to mi pomogło, doprowadziło mnie do tego stackoverflow.com/questions/20746413/…
Omar N Shamali
3

Miałem ten sam problem. Problem polegał na tym, że performSegueWithIdentifier został wywołany przez powiadomienie, gdy tylko umieściłem powiadomienie w głównym wątku, komunikat ostrzegawczy zniknął.

Czerwony
źródło
3

Działa dobrze, spróbuj tego. Połączyć

UIViewController *top = [UIApplication sharedApplication].keyWindow.rootViewController;
[top presentViewController:secondView animated:YES completion: nil];
Vijay
źródło
3

Na wypadek, gdyby komukolwiek to pomogło, mój problem był wyjątkowo głupi. Oczywiście moja wina. Powiadomienie wyzwalało metodę wywołującą modal. Ale nie usunąłem powiadomienia poprawnie, więc w pewnym momencie miałem więcej niż jedno powiadomienie, więc modal byłby wywoływany wiele razy. Oczywiście po jednorazowym wywołaniu modalu kontroler widoku, który go nazywa, nie znajduje się już w hierarchii widoków, dlatego widzimy ten problem. Moja sytuacja spowodowała także wiele innych problemów, jak można się spodziewać.

Podsumowując, cokolwiek robisz, upewnij się, że modal nie zostanie wywołany więcej niż raz .

HotFudgeSunday
źródło
3

Skończyło się na takim kodzie, który w końcu działa dla mnie (Swift), biorąc pod uwagę, że chcesz wyświetlić niektóre viewControllerz dowolnego miejsca. Ten kod oczywiście zawiesi się, gdy nie będzie dostępny rootViewController, to jest otwarte zakończenie. Nie obejmuje również zwykle wymaganego przejścia na wątek interfejsu użytkownika za pomocą

dispatch_sync(dispatch_get_main_queue(), {
    guard !NSBundle.mainBundle().bundlePath.hasSuffix(".appex") else {
       return; // skip operation when embedded to App Extension
    }

    if let delegate = UIApplication.sharedApplication().delegate {
        delegate.window!!.rootViewController?.presentViewController(viewController, animated: true, completion: { () -> Void in
            // optional completion code
        })
    }
}
igraczech
źródło
BTW, aby zrozumieć, skąd mam wywołać tę metodę z ... jest to biblioteka SDK bez interfejsu użytkownika, która wyświetla własny interfejs użytkownika w aplikacji w określonym (nieujawnionym) przypadku.
igraczech
Spowodujesz awarię i spalenie, jeśli ktoś zdecyduje się osadzić sdk w aplikacji, która ma rozszerzenie. Przekaż UIViewController do nadużycia w tobie sdk init method [s].
Anton Tropashko,
Jesteś prawdziwym Antonem. Ten kod został napisany, gdy rozszerzenia nie istniały, a SDK nie jest jeszcze używany w żadnym z nich. Dodałem klauzulę ochronną, aby pominąć ten przypadek.
igraczech
3

Ten rodzaj ostrzeżenia może oznaczać, że próbujesz obecnego nowego View Controllerthrough Navigation Controllerpodczas gdy ten Navigation Controllerjest obecnie prezentuje inny View Controller. Aby to naprawić, musisz View Controllernajpierw odrzucić prezentację, a po jej zakończeniu przedstawić nową. Inną przyczyną ostrzeżenia może być próba przedstawienia View Controllerw wątku innej niż main.

saltwat5r
źródło
2

Naprawiłem to, przenosząc start()funkcję do dismissbloku uzupełniania:

self.tabBarController.dismiss(animated: false) {
  self.start()
}

Start zawiera dwa połączenia z self.present()jednym dla UINavigationController i drugim dla UIImagePickerController.

To naprawiło to dla mnie.

Alper
źródło
2

Miałem podobny problem na Swift 4.2, ale mój widok nie był prezentowany z cyklu widoków. Przekonałem się, że miałem wiele segmentów do zaprezentowania w tym samym czasie. Więc użyłem dispatchAsyncAfter.

func updateView() {

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in

// for programmatically presenting view controller 
// present(viewController, animated: true, completion: nil)

//For Story board segue. you will also have to setup prepare segue for this to work. 
 self?.performSegue(withIdentifier: "Identifier", sender: nil)
  }
}
Ashim Dahal
źródło
1

Możesz również otrzymać to ostrzeżenie podczas wykonywania segue z kontrolera widoku, który jest osadzony w kontenerze. Prawidłowym rozwiązaniem jest użycie segue od rodzica kontenera, a nie od kontrolera widoku kontenera.

Borzh
źródło
1

Muszę napisać poniżej linii.

self.searchController.definesPresentationContext = true

zamiast

self.definesPresentationContext = true

w UIViewController

Coder_A_D
źródło
1

Z Swift 3 ...

Inną możliwą przyczyną tego, co mi się przydarzyło, było przechodzenie od tableViewCell do innego ViewController na Storyboard. Użyłem również, override func prepare(for segue: UIStoryboardSegue, sender: Any?) {}gdy komórka została kliknięta.

Rozwiązałem ten problem, tworząc segment z ViewController do ViewController.

Devbot10
źródło
1

Miałem ten problem, a główną przyczyną było wielokrotne subskrybowanie modułu obsługi kliknięć przycisków (TouchUpInside).

Subskrybował w ViewWillAppear, który był wywoływany wiele razy, ponieważ dodaliśmy nawigację, aby przejść do innego kontrolera, a następnie zrelaksować się z powrotem.

Wes
źródło
1

Zdarzyło mi się, że segue w serii ujęć był zepsuty . Usunięcie segue (i ponowne utworzenie dokładnie tego samego segregacji) rozwiązało problem.

vonox7
źródło
1

W głównym oknie prawdopodobnie zawsze będą czasy z przejściami, które są niezgodne z wyświetlaniem alertu. Aby umożliwić prezentowanie alertów w dowolnym momencie cyklu życia aplikacji, powinieneś mieć osobne okno do wykonania zadania.

/// independant window for alerts
@interface AlertWindow: UIWindow

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message;

@end

@implementation AlertWindow

+ (AlertWindow *)sharedInstance
{
    static AlertWindow *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[AlertWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    });
    return sharedInstance;
}

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message
{
    // Using a separate window to solve "Warning: Attempt to present <UIAlertController> on <UIViewController> whose view is not in the window hierarchy!"
    UIWindow *shared = AlertWindow.sharedInstance;
    shared.userInteractionEnabled = YES;
    UIViewController *root = shared.rootViewController;
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    alert.modalInPopover = true;
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        shared.userInteractionEnabled = NO;
        [root dismissViewControllerAnimated:YES completion:nil];
    }]];
    [root presentViewController:alert animated:YES completion:nil];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    self.userInteractionEnabled = NO;
    self.windowLevel = CGFLOAT_MAX;
    self.backgroundColor = UIColor.clearColor;
    self.hidden = NO;
    self.rootViewController = UIViewController.new;

    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(bringWindowToTop:)
                                               name:UIWindowDidBecomeVisibleNotification
                                             object:nil];

    return self;
}

/// Bring AlertWindow to top when another window is being shown.
- (void)bringWindowToTop:(NSNotification *)notification {
    if (![notification.object isKindOfClass:[AlertWindow class]]) {
        self.hidden = YES;
        self.hidden = NO;
    }
}

@end

Podstawowe użycie, które z założenia zawsze będzie skuteczne:

[AlertWindow presentAlertWithTitle:@"My title" message:@"My message"];
Cœur
źródło
1

Niestety przyjęte rozwiązanie nie zadziałało w moim przypadku. Próbowałem przejść do nowego kontrolera widoku zaraz po odprężeniu z innego kontrolera widoku.

Znalazłem rozwiązanie, używając flagi, aby wskazać, który wywoływano segue odwijania.

@IBAction func unwindFromAuthenticationWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToMainTabBar = true
}

@IBAction func unwindFromForgetPasswordWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToLogin = true
}

Następnie zaprezentuj poszukiwany VC present(_ viewControllerToPresent: UIViewController)

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    if self.shouldSegueToMainTabBar {
        let mainTabBarController = storyboard.instantiateViewController(withIdentifier: "mainTabBarVC") as! MainTabBarController
        self.present(mainTabBarController, animated: true)
        self.shouldSegueToMainTabBar = false
    }
    if self.shouldSegueToLogin {
        let loginController = storyboard.instantiateViewController(withIdentifier: "loginVC") as! LogInViewController
        self.present(loginController, animated: true)
        self.shouldSegueToLogin = false
    }
}

Zasadniczo powyższy kod pozwoli mi złapać odprężenie przy logowaniu / SignUp VC i przejść do deski rozdzielczej lub złapać akcję odprężania od zapomnienia hasła VC i przejść do strony logowania.

Fan Jin
źródło
1

Naprawiłem ten błąd polegający na zapisywaniu najwyższego kontrolera widoku w stałą, który można znaleźć w trakcie cyklu nad rootViewController:

if var topController = UIApplication.shared.keyWindow?.rootViewController {
    while let presentedViewController = topController.presentedViewController {
        topController = presentedViewController
    }
    topController.present(controller, animated: false, completion: nil)
    // topController should now be your topmost view controller
}
Marek Baláž
źródło
1

Znalazłem ten błąd, który pojawił się po aktualizacji Xcode, wierzę w Swift 5 . Problem pojawił się, gdy programowo uruchomiłem segue bezpośrednio po rozwinięciu kontrolera widoku.

Rozwiązanie pojawiło się podczas naprawy powiązanego błędu, który polegał na tym, że użytkownik mógł teraz odwijać segu, przesuwając stronę w dół. To złamało logikę mojego programu.

Zostało to naprawione poprzez zmianę trybu prezentacji na wszystkich kontrolerach widoku z Automatycznego na Pełny ekran .

Możesz to zrobić w panelu atrybutów w kreatorze interfejsów. Lub zobacz tę odpowiedź, aby dowiedzieć się, jak to zrobić programowo.

Tim MB
źródło
0

Właśnie miałem ten problem, ale nie miało to nic wspólnego z czasem. Użyłem singletona do obsługi scen i ustawiłem go jako prezentera. Innymi słowy „jaźń” nie była do niczego podłączona. Właśnie stworzyłem jej „scenę” nowym prezenterem i voila, zadziałało. (Voila traci kontakt, gdy nauczysz się jego znaczenia, heh).

Więc tak, nie chodzi o „magiczne znalezienie właściwej drogi”, ale o zrozumienie, gdzie stoi twój kod i co robi. Cieszę się, że Apple dał tak jednoznacznie angielski komunikat ostrzegawczy, nawet z emocjami. Uznanie dla twórcy jabłek, który to zrobił !!

Stephen J.
źródło
0

Jeśli z jakiegoś powodu inne rozwiązania nie wyglądają dobrze, nadal możesz użyć tego starego dobrego workaroundprezentowania z opóźnieniem 0, na przykład:

dispatch_after(0, dispatch_get_main_queue(), ^{
    finishViewController *finished = [self.storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];
    [self presentViewController:finished animated:NO completion:NULL];    
});

Chociaż nie widziałem żadnej udokumentowanej gwarancji, że Twój VC będzie w hierarchii widoków w bloku wysłania czasu, który jest zaplanowany do wykonania, zauważyłem, że będzie dobrze.

Opcjonalne jest również użycie opóźnienia wynoszącego np. 0,2 sekundy. I najlepsza rzecz - w ten sposób nie musisz zadzierać ze zmienną logicznąviewDidAppear:

Dannie P.
źródło
2
Chociaż może to działać teraz, nie ma gwarancji, że Apple zmieni zachowanie i złamie to w przyszłości. Następnie, gdy wrócisz do kodu i spróbujesz naprawić błędy, będziesz się zastanawiać, dlaczego robisz to pozornie niepotrzebne wysyłanie.
Cruinh
Wysłanie z czasem 0 już mnie zaoszczędziło wiele razy - czasem rzeczy, które logicznie powinny działać, normalnie bez nich nie działają. Więc po prostu komentuj dla siebie i innych, dlaczego robisz nieoczywiste rzeczy (nie tylko taką wysyłkę) i powinieneś być w porządku.
Dannie P
2
Hakujesz tylko ten problem i nie rozwiązujesz go.
Michael Peterson
0

Działa to w celu przedstawienia dowolnego kontrolera widoku, jeśli masz dostępny kontroler nawigacji. self.navigationController? .present (MyViewController, animowany: true, ukończenie: zero) Ponadto mogę również przedstawiać alerty i kontroler poczty.

Gurpreet Singh
źródło