AppDelegate, rootViewController et presentViewController

je fais le tutoriel d'intégration Facebook, Je veux montrer mon Controller MainViewViewController si l'Utilisateur a un token valide pour l'état actuel sinon je veux montrer LoginViewController.

MainViewAppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if (FBSession.activeSession.state == FBSessionStateCreatedTokenLoaded) {
        // To-do, show logged in view
    } else {
        // No, display the login page.
        [self showLoginView];
    }
    return YES;
}
- (void)showLoginView
{
    UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"          bundle:nil];
    LoginViewController* loginViewController = [mainstoryboard      instantiateViewControllerWithIdentifier:@"LoginViewController"];
    [self.window.rootViewController presentViewController:loginViewController animated:YES completion:NULL];
}

erreur de Console:

Warning: Attempt to present <LoginViewController: 0xb492fd0> on <MainViewViewController: 0xb1bd820> whose view is not in the window hierarchy!

Je ne veux pas utiliser un contrôleur de navigation.

38
demandé sur Community 2012-11-17 15:35:48

5 réponses

j'ai eu le même problème. Sur la base de la réponse à cette question , j'ai ajouté [self.window makeKeyAndVisible] juste avant presentViewController:animated:completion: , et cela m'a corrigé.

dans votre cas, showLoginView devient

- (void)showLoginView
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:@"LoginViewController"];
    [self.window makeKeyAndVisible];
    [self.window.rootViewController presentViewController:loginViewController animated:YES completion:NULL];
}
128
répondu shebang 2017-05-23 12:18:17

présentant parfois le contrôleur de vue modale depuis la fenêtre.rootViewController peut produire le même avertissement et n'avoir aucun effet. Exemple d'une telle hiérarchie de contrôleurs de vue:

  1. [ Myuitable ViewController ] (modally presented by MYUIViewController )
  2. [ MYUIViewController ] (rootViewController of UINavigationController below)
  3. [ UINavigationController ] (root)

maintenant appel

[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:[UIViewController new] animated:YES completion:nil];

va causer cet avertissement exact (testé à la fois sur iOS6 & 7 Sim)

Solution: Au lieu d'utiliser rootViewController-utilisez le top présenté par lui:

    UIViewController *topRootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
    while (topRootViewController.presentedViewController) 
    {
        topRootViewController = topRootViewController.presentedViewController;
    }

    [topRootViewController presentViewController:yourController animated:YES completion:nil];
  • parfois, le clavier peut avoir été remplacé par une fenêtre avec zéro rootViewController (montrant UIAlertViews, UIActionSheets sur iPhone, etc), dans ce cas, vous devez utiliser la propriété window D'UIView.
34
répondu Stepan Generalov 2014-01-23 01:46:13

la réponse de Stepan Generalov était la bonne pour moi dans Swift 3 !!!

Bien sûr, avec la nouvelle syntaxe etc. donc je vais le Copier ici:

let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "MainApp") as! ViewController

var topRootViewController: UIViewController = (UIApplication.shared.keyWindow?.rootViewController)!
while((topRootViewController.presentedViewController) != nil){
    topRootViewController = topRootViewController.presentedViewController!
}
topRootViewController.present(vc, animated: true, completion: nil)

"MainApp" est ma principale-vue-contrôleur de l'identifiant dans ce cas.



Je sais qu'il y a d'autres moyens, mais si vous avez besoin d'avoir des systèmes D'URL différents pour l'ouverture différentes parties de votre application, vous devez le manipuler dans AppDelegate donc c'est parfait parce que dans le

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {}

méthode, vous pouvez juste vérifier ce que url est comme une chaîne de caractères et ensuite décider si vous exécutez le code écrit ci-dessus ou peut-être un similaire avec un identifiant différent pour un autre contrôleur de vue ( withIdentifier )

3
répondu unixb0y 2017-05-23 12:10:30

Dans Swift 3: -

let storyboard = UIStoryboard(name: "Login", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
window?.makeKeyAndVisible()
window?.rootViewController?.present(viewController, animated: true, completion: nil)
0
répondu Jay Mehta 2017-09-15 11:42:35

au cas où, quand vous n'utilisez pas de storyboard. Vous devez d'abord créer YourViewController. Aller À Fichier -> Nouveau -> Fichier... (ou raccourci-commande + N) enter image description here

ensuite, choisissez la classe Cocoa Touch. Cliquez sur Suivant, ou entrez enter image description here

que le nom de type pour votre viewController et cliquez Suivant enter image description here

#import "AppDelegate.h"
#import "YourViewController.h"

@interface AppDelegate ()

@end

@implementaion AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

// Init window
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
[self.window makeKeyAndVisible];

// Init YourViewController
YourViewController *viewController = [[YourViewController alloc] init];

// Init YourNavigationController
UINavigationController *navigationContoller = [[UINavigationController alloc] initWithRootViewController: viewController];

// Set rootViewController
self.window.rootViewController = navigationContoller;

return YES;

}

@end

Swift 3/4 Exemple

import UIKit

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

//1-st step
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()

//2-nd - create a window root controller, and create a layout
let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))

return true

}

0
répondu Alex Kolovatov 2018-04-05 08:59:02