Warnung: Versuchen Sie, * on * zu präsentieren, dessen Ansicht nicht in der Fensterhierarchie enthalten ist - schnell


83

Ich versuche zu präsentieren, ViewController ob im Datenmodell gespeicherte Daten vorhanden sind. Aber ich bekomme folgenden Fehler:

Warnung: Versuchen Sie, * on * zu präsentieren, dessen Ansicht nicht in der Fensterhierarchie enthalten ist. "

Relevanter Code:

override func viewDidLoad() {
    super.viewDidLoad()
    loginButton.backgroundColor = UIColor.orangeColor()

    var request = NSFetchRequest(entityName: "UserData")
    request.returnsObjectsAsFaults = false

    var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context:NSManagedObjectContext = appDel.managedObjectContext!

    var results:NSArray = context.executeFetchRequest(request, error: nil)!

    if(results.count <= 0){
        print("Inga resultat")
    } else {
        print("SWITCH VIEW PLOX")
        let internVC = self.storyboard?.instantiateViewControllerWithIdentifier("internVC") as internViewController
        self.presentViewController(internVC, animated: true, completion: nil)
    }
}

Ich habe verschiedene mit Google gefundene Lösungen ohne Erfolg ausprobiert.


Haben Sie Ihren ViewController im Storyboard verbunden? Sie verwenden hier einen NavigationController?
derdida

Was meinst du damit, wenn ich meine ViewControllerin Storyboard verbunden habe ? Ich benutze nicht NavigationController@derdida
Nils Wasell

Versuchen Sie: self.addChildViewController (childController: UIViewController) in ViewDidLoad
derdida

Dies erzeugt einen Fehler. Es erwartet einen Mitgliedsnamen oder einen Konstruktoraufruf nach "Typname" (Das UIViewControllerTeil). @derdida
Nils Wasell

Wo hast du das geschrieben? In ViewDidLoad Ihres MainViewControllers?
derdida

Antworten:


126

Zu diesem Zeitpunkt in Ihrem Code wurde die Ansicht des Ansichtscontrollers nur erstellt, aber keiner Ansichtshierarchie hinzugefügt. Wenn Sie von diesem Ansichts-Controller aus so schnell wie möglich präsentieren möchten, sollten Sie dies tun viewDidAppear, um die Sicherheit zu gewährleisten.


2
Wenn ich es in viewDidAppear einfüge, ruft es beim Schließen des präsentierten ViewControllers die viewDidAppear-Methode erneut auf und präsentiert den viewController erneut. Ich habe eine Problemumgehung, eine bedingte Anweisung vor dem Präsentieren einzufügen, aber es gibt eine Möglichkeit, anstatt eine zu setzen bedingte Aussage?
Puneet

2
Ich würde sagen, dass der Versuch, ein anderes modales Recht zu präsentieren, wenn ein Bildschirm erscheint, zunächst ein seltsames Verhalten ist, daher ist ein State Bool kaum die schlechteste Lösung. Denken Sie gleichzeitig über den Grund nach, warum Sie das Modal anzeigen müssen, und prüfen Sie, ob Sie auf diese Informationen zugreifen können.
Acey

2
Wenn Sie dies in viewWillAppear tun, haben Sie die Situation, in der es sich mitten in der Präsentation befindet, wenn Sie Ihre Präsentation starten. Eine Alternative wäre, es in viewWillAppear einzufügen, aber die in iOS 8 neue TransitionCoordinator-Eigenschaft zu verwenden, um den Code nach Abschluss des Übergangs hinzuzufügen. Weitere Informationen finden Sie hier developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Acey

36

In Ziel c: Dies hat mein Problem gelöst, als Viewcontroller auf mpmovieplayer angezeigt wurde

- (UIViewController*) topMostController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

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

    return topController;
}

34

Swift 3

Ich hatte dies immer wieder als Neuling und fand heraus, dass die Gegenwart modale Ansichten lädt, die verworfen werden können, aber ein Wechsel zum Root-Controller ist am besten, wenn Sie kein Modal anzeigen müssen.

Ich habe das benutzt

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc  = storyboard?.instantiateViewController(withIdentifier: "MainAppStoryboard") as! TabbarController
present(vc, animated: false, completion: nil)

Verwenden Sie dies stattdessen mit meinem tabController:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let view = storyboard.instantiateViewController(withIdentifier: "MainAppStoryboard") as UIViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//show window
appDelegate.window?.rootViewController = view

Passen Sie einfach einen Ansichts-Controller an, wenn Sie zwischen mehreren Storyboard-Bildschirmen wechseln müssen.


16

Swift 3.

Rufen Sie diese Funktion auf, um den obersten Ansichts-Controller zu erhalten, und lassen Sie diesen Ansichts-Controller dann vorhanden.

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
        while (topController.presentedViewController != nil) {
            topController = topController.presentedViewController!
        }
        return topController
    }

Verwendung:

let topVC = topMostController()
let vcToPresent = self.storyboard!.instantiateViewController(withIdentifier: "YourVCStoryboardID") as! YourViewController
topVC.present(vcToPresent, animated: true, completion: nil)

1
Vielen Dank an Jacob Davis dafür! Ich habe es verwendet, um einen alertController zu präsentieren, weil ich die Warnung erhalten habe: Versuch zu präsentieren ....
Gary Mansted

Das ist sehr nützlich. Einige, die Controller präsentieren Aber Bildschirm wird nicht angezeigt. plötzlich wird es entlassen. Muss ein anderer Code implementiert werden? Bitte vorschlagen
Seethalakshmi_user8943692

13

für SWIFT

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
Vielen Dank! Dies war das einzige, was diesen Fehler für mich gelöst hat. Ich habe versucht, eine modale VC von einer Funktion zu präsentieren, die von einem Gestenerkenner ausgelöst wurde, lange nachdem die Ansicht vollständig geladen war (in Xcode 8 / iOS 10). Seltsamerweise ist die topControllervon dieser Funktion zurückgegebene VC genau dieselbe VC wie selfbeim Versuch, direkt mit zu präsentieren self.presentViewController(myModalVC), aber es gibt keinen Fehler in der Ansichtshierarchie, wenn ich die präsentierende VC mit Ihrer Funktion übergebe.
Natalia

13

Sie müssen nur einen Selektor mit einer Verzögerung ausführen - (0 Sekunden funktionieren).

override func viewDidLoad() {
    super.viewDidLoad()
    perform(#selector(presentExampleController), with: nil, afterDelay: 0)
}

@objc private func presentExampleController() {
    let exampleStoryboard = UIStoryboard(named: "example", bundle: nil)
    let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleVC") as! ExampleVC
    present(exampleVC, animated: true) 
}

Danke vielmals. Ich blieb über eine Stunde in diesem Problem stecken.
Reza

Vielen Dank ... @objc func presentExampleController ()
William Choy

Ich denke, es ist eine erstaunliche Antwort!
Mazend

Das ist ein Hack (der jetzt vielleicht funktioniert), aber Sie werden auf etwas vorbereitet, das in unerwarteten Fällen kaputt geht.
William Grand

6

Swift 4

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
Eine Erklärung und ein Beispiel wären hilfreich @AllenWixted
Eury Pérez Beltré

2

Für Swift 3.0 und höher

public static func getTopViewController() -> UIViewController?{
if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
  return topController
}
return nil}

2

Ich habe diesen Fehler beim Präsentieren des Controllers erhalten, nachdem der Benutzer den Deeplink geöffnet hat. Ich weiß, dass dies nicht die beste Lösung ist, aber wenn Sie sich in einem kurzen Zeitrahmen befinden, finden Sie hier eine schnelle Lösung - wickeln Sie einfach Ihren Code ein asyncAfter:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.7, execute: { [weak self] in
                                navigationController.present(signInCoordinator.baseController, animated: animated, completion: completion)
                            })

Es gibt Ihrem präsentierenden Controller Zeit, ihn anzurufen viewDidAppear.


1
let storyboard = UIStoryboard(name: "test", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "teststoryboard") as UIViewController
UIApplication.shared.keyWindow?.rootViewController?.present(vc, animated: true, completion: nil)

Dies schien zu funktionieren, um sicherzustellen, dass es die oberste Ansicht ist.

Ich habe einen Fehler bekommen

Warnung: Versuchen Sie, myapp.testController: 0x7fdd01703990 auf myapp.testController: 0x7fdd01703690 zu präsentieren, dessen Ansicht nicht in der Fensterhierarchie enthalten ist!

Hoffe das hilft anderen mit Swift 3


1

Ich habe so viele Ansätze ausprobiert! das einzig nützliche ist:

if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
}

1

Alle Implementierungen für topViewController hier unterstützen Fälle nicht vollständig, wenn Sie UINavigationControlleroder habenUITabBarController für diese beiden benötigen Sie eine etwas andere Behandlung:

Für UITabBarControllerundUINavigationController Sie benötigen eine andere Implementierung.

Hier ist Code, den ich verwende, um topMostViewController zu erhalten:

protocol TopUIViewController {
    func topUIViewController() -> UIViewController?
}

extension UIWindow : TopUIViewController {
    func topUIViewController() -> UIViewController? {
        if let rootViewController = self.rootViewController {
            return self.recursiveTopUIViewController(from: rootViewController)
        }

        return nil
    }

    private func recursiveTopUIViewController(from: UIViewController?) -> UIViewController? {
        if let topVC = from?.topUIViewController() { return recursiveTopUIViewController(from: topVC) ?? from }
        return from
    }
}

extension UIViewController : TopUIViewController {
    @objc open func topUIViewController() -> UIViewController? {
        return self.presentedViewController
    }
}

extension UINavigationController {
    override open func topUIViewController() -> UIViewController? {
        return self.visibleViewController
    }
}

extension UITabBarController {
    override open func topUIViewController() -> UIViewController? {
        return self.selectedViewController ?? presentedViewController
    }
}

1

Schnelle Methode, und liefern Sie eine Demo.

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

func demo() {
    let vc = ViewController()
    let nav = UINavigationController.init(rootViewController: vc)
    topMostController().present(nav, animated: true, completion: nil)
}

1

Die Verwendung des Hauptthreads zum Präsentieren und Entlassen des View Controllers hat bei mir funktioniert.

DispatchQueue.main.async { self.present(viewController, animated: true, completion: nil) }

0

Anstatt einen Draufsicht-Controller zu finden, kann man ihn verwenden

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

Wo viewController der Controller ist, den Sie präsentieren möchten Dies ist nützlich, wenn es verschiedene Arten von Ansichten in der Hierarchie gibt, wie TabBar, NavBar, obwohl andere korrekt, aber eher hackisch zu sein scheinen

Den anderen Präsentationsstil finden Sie in Apple Doc


0

Die vorherigen Antworten beziehen sich auf die Situation, in der der Ansichtscontroller, der eine Ansicht 1) darstellen soll, noch nicht zur Ansichtshierarchie hinzugefügt wurde oder 2) nicht der Draufsichtcontroller ist.
Eine andere Möglichkeit besteht darin, dass eine Warnung angezeigt wird, während eine andere Warnung bereits angezeigt und noch nicht verworfen wird.


0

Swift 5.1 :

let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let mainViewController = storyboard.instantiateViewController(withIdentifier: "ID")
let appDeleg = UIApplication.shared.delegate as! AppDelegate
let root = appDeleg.window?.rootViewController as! UINavigationController
root.pushViewController(mainViewController, animated: true)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.