31
votes

In one of my apps, I'm calling a viewController from the application didReceiveLocalNotification method. The page loads successfully, but it shows a warning as :

 Warning: Attempt to present <blankPageViewController: 0x1fda5190> on 
 <ViewController: 0x1fd85330> whose view is not in the window hierarchy!

My code is as follows :

 -(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {

    blankPageViewController *myView = [[blankPageViewController alloc] 
               initWithNibName:@"blankPageViewController" bundle: nil];
    myView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
    [self.viewController presentViewController:myView animated:NO completion:nil];  
}
9
When you are calling didReceiveLocalNotification?βhargavḯ
@Bhargavi : its a deligate that gets called when local notification are received.Krishna Raj Salim

9 Answers

21
votes

Finally I solved that issue with the following code.

-(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
       self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
       self.blankviewController = [[blankPageViewController alloc] initWithNibName:@"blankPageViewController" bundle:nil];
       self.window.rootViewController = self.blankviewController;
       [self.window makeKeyAndVisible];
}
15
votes

Put

[self.viewController presentViewController:myView animated:NO completion:nil];  

into a function e.g.

- (void)yourNewFunction
{
    [self.viewController presentViewController:myView animated:NO completion:nil];
}

and then call it like this:

[self performSelector:@selector(yourNewFunction) withObject:nil afterDelay:0.0];

The problem got described here and why does this performSelector:withObject:afterDelay fix this problem? Because the selector will not be called until the next run of the run loop. So things have time to settle down and you will just skip one run loop.

14
votes

As per my assumption, I am feeling like you are trying to present myView from self.viewController before self.viewController is attached or placed in window hierarchy. So just make sure to present myView after self.viewController gets appear/attached to window.

Why can't a modal view controller present another in viewDidLoad?

2
votes

it could be because the viewcontroller's view is not currently loaded in window hierarchy when VC is presented...

-(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
    rootViewController = [[navigationController viewControllers] objectAtIndex:0];
    blankPageViewController *myView = [[blankPageViewController alloc] initWithNibName:@"blankPageViewController" bundle: nil];
    [rootViewController presentModalViewController:myView animated:YES];
}
2
votes

I was having a similar issue, I was calling the presentViewController from within my AppDelegate.m when the application entered the foreground:

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    NSDate * lastActive = [[NSUserDefaults standardUserDefaults] objectForKey:@"lastActive"];

    double interval = [[NSDate date] timeIntervalSinceDate:lastActive];

    NSLog(@"Time Interval: %f", interval);

    if (interval > 900) { // interval is in seconds, so 900 seconds = 15 mins
        Login *pres = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"login"];

        UINavigationController *navi = ((UINavigationController*)self.window.rootViewController);
        if (navi.presentedViewController) {
            [navi dismissViewControllerAnimated:YES completion:^{
                [navi presentViewController:pres animated:NO completion:nil];
            }];
        } else {
            [navi presentViewController:pres animated:NO completion:nil];
        }
    }
}

This worked no problem as it dismisses the view controller first (regardless of what views have been pushed onto it) if it is present before presenting the Login view controller. If not then I can just present the Login view controller straight away.

1
votes

Edge Case:

Some people may find this through Google and it is worth pointing out that sometimes this error is raised if you are loading a view up as the root view controller which is not labelled as the initial view in Storyboard (& another view is) and then you load another view on top. Eg, in Log In Views which are loaded programmatically from within the applicationdidfinish... method of the App Delegate. Simply change the initial view (drag the arrow in Storyboard) to the appropriate one for your hierarchy. Esoteric, vague, but worth pointing out.

0
votes

If your application type id UINavigationController then you can use.

-(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {

blankPageViewController *myView = [[blankPageViewController alloc]
                                   initWithNibName:@"blankPageViewController" bundle: nil];
myView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self.navigationController presentViewController:myView animated:NO completion:nil]; }

Hope this will help you. All the best !!!

0
votes

For Swift 2.0 I used an override for viewDidAppear with:

let vc = self.storyboard?.instantiateViewControllerWithIdentifier("Second") as! SecondViewController

self.presentViewController(vc, animated: true, completion: nil)

Where "Second" is storyboard ID of the SecondViewController in the identity inspector.

0
votes
I have used Navigation Controller and on which i have used a
ModalViewController to present a Popup(Present over current context). 
From this Popup i am opening a ViewController Modally which 
caused the Warning. So to resolve i did below change:

[self.presentedViewController performSegueWithIdentifier:@"PresentScreenSegueId" sender:sender];