刚开始使用Xcode 4.5,我在控制台得到了这个错误:
警告:试图在< ViewController: 0x1ec3e000>上显示< finishViewController: 0x1e56e0a0 >,其视图不在窗口层次结构中!
视图仍在显示,应用程序中的一切都在正常工作。这是iOS 6的新功能吗?
这是我用来在视图之间更改的代码:
UIStoryboard *storyboard = self.storyboard;
finishViewController *finished =
[storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];
[self presentViewController:finished animated:NO completion:NULL];
你只能有1个rootViewController,它是最近出现的一个。所以不要尝试让一个视图控制器呈现另一个视图控制器当它已经呈现了一个没有被解散的视图控制器。
在做了一些自己的测试之后,我得出了一个结论。
如果你有一个rootViewController你想要显示所有东西,那么你就会遇到这个问题。
下面是我的rootController代码(打开是从根节点显示视图控制器的快捷方式)。
func open(controller:UIViewController)
{
if (Context.ROOTWINDOW.rootViewController == nil)
{
Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
Context.ROOTWINDOW.makeKeyAndVisible()
}
ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}
如果我在一行中调用open两次(不管时间流逝),这将在第一个开放上工作,但不是在第二个开放上。第二次打开尝试将导致上述错误。
然而,如果我关闭最近呈现的视图然后调用open,当我再次调用open(在另一个视图控制器上)时,它工作得很好。
func close(controller:UIViewController)
{
ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}
我的结论是,只有MOST-RECENT-CALL的rootViewController在视图层次结构上(即使您没有解散它或删除视图)。我试着玩所有的加载器调用(viewDidLoad, viewDidAppear,并做延迟调度调用),我发现我能让它工作的唯一方法是从最顶层的视图控制器调用present。
遗憾的是,这个公认的解决方案并不适用于我的案例。我试图在从另一个视图控制器unwind后导航到一个新的视图控制器。
我找到了一个解决方案,使用一个标志来指示哪个unwind segue被调用。
@IBAction func unwindFromAuthenticationWithSegue(segue: UIStoryboardSegue) {
self.shouldSegueToMainTabBar = true
}
@IBAction func unwindFromForgetPasswordWithSegue(segue: UIStoryboardSegue) {
self.shouldSegueToLogin = true
}
然后用present(_ viewcontrollertoppresent: UIViewController)来呈现想要的VC
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if self.shouldSegueToMainTabBar {
let mainTabBarController = storyboard.instantiateViewController(withIdentifier: "mainTabBarVC") as! MainTabBarController
self.present(mainTabBarController, animated: true)
self.shouldSegueToMainTabBar = false
}
if self.shouldSegueToLogin {
let loginController = storyboard.instantiateViewController(withIdentifier: "loginVC") as! LogInViewController
self.present(loginController, animated: true)
self.shouldSegueToLogin = false
}
}
基本上,上面的代码将让我从login/SignUp VC捕获unwind并导航到仪表板,或者从forget password VC捕获unwind操作并导航到登录页面。