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.
À 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.
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;
}
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.
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)
}
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)
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
}
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}
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
.
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!
}
}
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
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
}
}
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
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.