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呈现模态视图控制器可能会产生相同的警告,并没有任何效果。 这种视图控制器层次结构的例子:
- [ MYUITableViewController ](由MYUIViewController提供)
- [ MYUIViewController ](下面的UINavigationController的rootViewController)
- [ 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)