web-dev-qa-db-fra.com

Avertissement: Essayez de présenter * sur * dont la vue ne se trouve pas dans la hiérarchie des fenêtres - swift

J'essaie de présenter une ViewController si le modèle de données contient des données sauvegardées. Mais j'obtiens l'erreur suivante: 

Avertissement: Tentative de présentation * sur * dont la vue ne figure pas dans la hiérarchie des fenêtres " 

Code pertinent:

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)
    }
}

J'ai essayé différentes solutions trouvées avec Google sans succès.

74
Nils Wasell

À ce stade de votre code, la vue du contrôleur de vue a été créée mais n'a été ajoutée à aucune hiérarchie de vue. Si vous souhaitez présenter le contrôleur de vue le plus rapidement possible, vous devez le faire dans viewDidAppear pour être le plus sûr. 

110
Acey

En Objective C: Cela a résolu mon problème lorsque je présentais viewcontroller au dessus de mpmovieplayer

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

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

    return topController;
}
32
akr ios

Swift 3

En tant que débutant, j’en ai fait l’objet et j’ai trouvé que les vues modales actuelles peuvent être rejetées, mais il est préférable de passer au contrôleur racine si vous n’avez pas besoin de montrer de mode. 

J'utilisais ceci

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

En utilisant ceci à la place avec mon 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

Adaptez-vous simplement à un contrôleur de vue si vous devez basculer entre plusieurs écrans de scénarimage.

28
Jason

Vous devez juste effectuer un sélecteur avec un délai - (0 secondes fonctionne). 

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) 
}
13
Edward

Rapide 3.

Appelez cette fonction pour obtenir le contrôleur de vue le plus élevé, puis ayez ce contrôleur de vue présent.

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

Usage:

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

pour Swift

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

Swift 4

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

Pour Swift 3.0 et supérieur

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

Je recevais cette erreur alors que je présentais le contrôleur après que l'utilisateur a ouvert le lien profond. Je sais que ce n'est pas la meilleure solution, mais si vous êtes dans un court laps de temps, voici une solution rapide - emballez simplement votre code dans asyncAfter:

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

Le contrôleur présentateur aura le temps d’appeler viewDidAppear.

1
Bohdan Savych

J'ai essayé tellement d'approches! la seule chose utile est:

if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
}
1
Xiaohan Chen
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)

Cela a semblé fonctionner pour s'assurer que c'est la vue la plus haute. 

Je recevais une erreur

Avertissement: Essayez de présenter myapp.testController: 0x7fdd01703990 sur myapp.testController: 0x7fdd01703690 dont la vue n'est pas dans la hiérarchie des fenêtres!

J'espère que cela aide les autres avec Swift 3

1
Jason

Toutes les implémentations de topViewController ici ne prennent pas totalement en charge les cas où vous avez UINavigationController ou UITabBarController, vous avez besoin d'un traitement un peu différent:

Pour UITabBarController et UINavigationController, vous avez besoin d'une implémentation différente.

Voici le code que j'utilise pour obtenir topMostViewController:

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
Grzegorz Krukowski

Plutôt que de trouver le contrôleur de vue de dessus, on peut utiliser

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

Où viewController est le contrôleur que vous souhaitez présenter Ceci est utile lorsqu'il existe différents types de vues dans la hiérarchie, comme TabBar, NavBar, bien que d'autres semblent être corrects, mais plus hachis

L’autre style de présentation se trouve sur doc Apple

0
Akhil Dad

Les réponses précédentes concernent la situation dans laquelle le contrôleur de vue devant présenter une vue 1) n'a pas encore été ajouté à la hiérarchie de la vue ou 2) n'est pas le contrôleur de vue de dessus.
Une autre possibilité est qu’une alerte soit présentée alors qu’une autre alerte est déjà présentée et n’a pas encore été rejetée.

0
Reinhard Männer