AppDelegate,rootViewController和presentViewController

我正在做的Facebook集成教程,我想显示我的MainViewViewController,如果用户有一个有效的标记为当前状态,否则我想显示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]; } 

控制台错误:

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

我不想使用NavigationController。

我遇到过同样的问题。 基于这个问题的答案,我在presentViewController:animated:completion:之前加了一个[self.window makeKeyAndVisible] presentViewController:animated:completion:并且为我解决了这个问题 。

在你的情况下,showLoginView成为

 - (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]; } 

有时从window.rootViewController呈现模态视图控制器可能会产生相同的警告,并没有任何效果。 这种视图控制器层次结构的例子:

  1. [ MYUITableViewController ](由MYUIViewController提供)
  2. [ MYUIViewController ](下面的UINavigationController的rootViewController)
  3. [ UINavigationController ](root)

现在打电话

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

会导致这个确切的警告(在iOS6和7模拟器上testing)

解决scheme:而不是使用rootViewController – 使用它提出的第一个:

  UIViewController *topRootViewController = [UIApplication sharedApplication].keyWindow.rootViewController; while (topRootViewController.presentedViewController) { topRootViewController = topRootViewController.presentedViewController; } [topRootViewController presentViewController:yourController animated:YES completion:nil]; 
  • 有时keyWindow可能已经被nil rootViewController(在iPhone上显示UIAlertViews,UIActionSheets等)的窗口取代,在这种情况下,你应该使用UIView的窗口属性。

Stepan Generalov的回答在Swift 3中对我来说是正确的!
当然,新的语法等,所以我会复制它在这里:

 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”是我主视图控制器的标识符。

我知道还有其他的方法,但如果你需要有不同的URLscheme来打开你的应用程序的不同部分,你必须在AppDelegate中处理它,所以这是完美的,因为在

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

方法,你可以只检查一下string是什么url ,然后决定是否执行上面的代码,也可能是一个类似的标识符为另一个视图控制器( withIdentifier

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