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.

Nils Wasell
quelle
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.

Acey
quelle
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;
}
akr ios
quelle
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.

Jason
quelle
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)
Jacob F. Davis C-CISO
quelle
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
}
Viennarz Valdevieso Curtiz
quelle
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) 
}
Edward
quelle
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
}
Allen Wixted
quelle
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}
Hiren Panchal
quelle
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.

Bohdan Savych
quelle
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

Jason
quelle
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!
  }
}
Xiaohan Chen
quelle
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
    }
}
Grzegorz Krukowski
quelle
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)
}
Zgpeace
quelle
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) }
Dinesh Sharma
quelle
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

Akhil Dad
quelle
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.

Reinhard Männer
quelle
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)
Bavafaali
quelle