This question already has answers here:
Attempt to present UIViewController on UIViewController whose view is not in the window hierarchy
(38 answers)
Closed 8 years ago.
I'm facing a problem trying to link my UIViewController but I got my final error.
Attempt to present ViewController whose view is not in the window hierarchy
Here's my code :
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Wokay"])
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"Vibes"];
[self.window.rootViewController presentViewController:vc animated:YES completion:nil];
}
}
Code Error:
Warning: Attempt to present <ViewController: 0x110634bc0> on <Login: 0x10951e7f0> whose view is not in the window hierarchy!
It seems like that your UIViewController(Login) is not in Window Hierarchy.
You may be adding your LoginViewController as a subView in UIWindow.
If so, set it as the UIWindow's rootViewController
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Other code parts
[self.window setRootViewController:loginViewController];
return YES;
}
OR
If you are adding LoginViewController's view as subView in any UIViewController(say FirstViewController), present it instead
In your FirstViewController.m,
-(void)viewDidLoad{
[super viewDidLoad];
LoginViewController *loginViewController ;//Instantiate LoginViewController here
[self presentViewController:loginViewController animated:NO completion:Nil];
}
Related
I'm trying to call a controller, if has response error, and redirect the user for login controller.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"EventManagerStoryboard" bundle:[NSBundle mainBundle]];
LoginViewController *loginController = [storyboard instantiateViewControllerWithIdentifier:#"loginID"];
[loginController viewDidLoad];
loginController.showOnlyLoginForm = YES;
[self presentViewController:loginController animated:YES completion:Nil];
and I facing this warning -
Attempt to present Attempt to present LoginViewController: 0x7fc958201130 on ProfileController: 0x7fc9583118e0 whose view is not in the window hierarchy!
Don't run this code in viewDidLoad try it in viewDidAppear
[self presentViewController:loginController animated:YES completion:Nil];
Edit:
use in appDelegate if you implement navigationController
[(UINavigationController *)self.window.rootViewController pushViewController:vc animated:YES];
I recently work on a tutorial for my app. I created the tutorial with this Tutorial:
http://www.appcoda.com/uipageviewcontroller-tutorial-intro/
I created a "button" which brings the user back to the rootViewController, in this case the TabBarController. Problem is: with this tutorial I made a extra storyboard for the tutorial. So how can I go back to the original rootViewController(TabBarController) with the button?
Code:
- (IBAction)start:(id)sender {
UIViewController* backToRootViewController = [[UIViewController alloc] initWithNibName:#"TabBarController" bundle:[NSBundle mainBundle]];
[self.view addSubview:backToRootViewController.view];
}
This does not work, too
- (IBAction)start:(id)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}
EDIT
To open the tutorial at the first start:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isAccepted = [standardUserDefaults boolForKey:#"iHaveAcceptedTheTerms"];
if (!isAccepted) {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[APPViewController alloc] initWithNibName:#"APPViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
}
APPViewController is the Tutorial
EDIT
After the help of johnnelm9r the current code is this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"main" bundle: nil];
IntroViewController *introViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"IntroViewController"];
BOOL isAccepted = [standardUserDefaults boolForKey:#"iHaveAcceptedTheTerms"];
if (!isAccepted) {
[self.window.rootViewController presentViewController:introViewController animated:NO completion:nil];
}
But now, sadly, the app crashed and the error is:
Application tried to present a nil modal view controller on target <UITabBarController: 0x175409d0>.'
and also a warning: Incompatible pointer type assigning to 'ViewController' from 'UIViewController' in AppDelegate
*****UPDATE****
I uploaded a sample project to demonstrate what I mean. You can find it here: github link
Good luck!
**** EDIT
After talking with you more I'd suggest trying to use something similar to this code in your viewDidAppear method of whatever view controller runs the first tab of your tabbarcontroller (obviously you want your own class name where I have IntroViewController):
BOOL didShowIntro = [[NSUserDefaults standardUserDefaults] boolForKey:#"showIntro"];
IntroViewController *introViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"IntroViewController"];
if (didShowIntro)
{
[self presentViewController:introViewController animated:NO completion:nil];
}
and then just pop the presented controller from your button in the tutorial like so:
[self dismissViewControllerAnimated:NO completion:nil];
Just remember to set your user defaults to no when you press the button in your tutorial view controller. And make sure you are going from tabbarcontroller to navigationcontroller as a relationship segue and then to the view controller you want to show after the tutorial as a root. Just to be clear: there should be no connection to the tutorial view controller on your storyboard.
Just to be extra clear: your storyboard should have the navbarcontroller as your initial view controller connected to a navigationcontroller connected to a view controller and another view controller not connected to anything. :) And make sure you delete the code in the delegate.
To go to rootViewController
[self.navigationController popToRootViewControllerAnimated:YES];
Guys in my app I have some code in the app delegate method application:didFinishLaunchingWithOptions: that determines if the initial View Controller should be the LoginViewController or the MainViewController.
If the LoginViewController is showed first and the user logs in successfully I show the MainViewController modally with this piece of code:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
FSMainViewController *vc = (MainViewController *)[storyBoard instantiateViewControllerWithIdentifier:#"MainViewController"];
vc.loginViewController = self;
[self presentViewController:vc animated:YES completion:nil];
What I want to do next, after the MainController is showed on the screen, is remove the LoginViewController from memory so in the viewWillApper:animated: method of the MainViewController I use this code to remove (or at least try to) the LoginViewController:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.loginViewController) {
[self.loginViewController dismissViewControllerAnimated:NO completion:nil];
}
}
Problem is that this code leads to strange behaviors like the MainViewController being removed from the screen and this error message showing up in the console.
Unbalanced calls to begin/end appearance transitions for <LoginViewController: 0xb06e350>
I also tried calling [self dismissViewControllerAnimated:NO completion:nil] in the completion block of the presentViewController:animated:completion method but still no luck, it didn't work.
What am I doing wrong? How can I remove from memory the underlying LoginViewController when the MainViewController is presented modally?
Don't present your main view controller if you want the login controller to go away, just make it the window's root view controller.
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
FSMainViewController *vc = (MainViewController *)[storyBoard instantiateViewControllerWithIdentifier:#"MainViewController"];
Self.window.rootViewController = VC;
You can't dismissViewController after presenting another one on it or its presentingViewController. At here, you should dismiss LoginViewController first, then present MainViewController.
Otherwise, if you'd like pushViewController, you can call [self.navigationController setViewControllers: animated:] to remove LoginViewController.
If you think presentingViewController is just what you want, try something like this in application:didFinishLaunchingWithOptions:
if (self.loginViewController) { //Define loginViewController in appDelegate.h
[self dismissViewControllerAnimated:NO completion:^{
[self presentViewController:mainViewController animated:YES completion:nil];
}];
}
else{
[self presentViewController:mainViewController animated:YES completion:nil];
}
I am trying to segue to my ViewController with this code:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"iPhone_Storyboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"details"];
[self presentViewController:vc animated:YES completion:nil];
However I get this error message:
Warning: Attempt to present <MyViewController: 0x10c5771a0> on <UINavigationController: 0x10c533da0> whose view is not in the window hierarchy!
I am calling the segue in the UIAlertView Delegate Method:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
}
Your UIAlertView's window is the frontmost UIWindow, so your view controller can't present. You need to wait until the alert view dismisses. The simplest way is to use alertView:didDismissWithButtonIndex: (instead of clickedButtonAtIndrx).
add this too, it worked for me.
lvc.modalPresentationStyle = UIModalPresentationFormSheet;
lvc.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[mvc presentModalViewController:lvc animated:YES];
I want to open a login screen and I have tried both programmatically and both with a segue.
I have seen similar questions but it didn't fix it for me.
Here are my two versions of code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
if (![[API sharedInstance] isAuthorized]) {
NSLog(#"I should Open login screen");
[self performSegueWithIdentifier:#"ShowLogin" sender:nil];
}
}
or
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
if (![[API sharedInstance] isAuthorized]) {
NSLog(#"I should Open login screen");
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
LoginScreen *vc = [sb instantiateViewControllerWithIdentifier:#"LoginScreen"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:vc animated:YES completion:NULL];
}
}
The segue is modal style.
In both cases the NSLog is printed and then I see a warning:
Warning: Attempt to present <LoginScreen: 0x1e5bd010> on <PhotoScreen: 0x1e5b82e0> whose view is not in the window hierarchy!
and the new view does not open.
Any hint on that?
Don't do this in viewDidLoad, your view isn't on screen yet, so that's why you get that error. You should do it in viewDidAppear (with no animation if you don't want to see the view of the controller that this code is in).