blundin
blundin

Reputation: 1643

Manual modal segue does not work, View Controller is not in the window hierarchy?

I've been searching the web and Stack Overflow for hours and I cannot resolve this issue. here's hoping you all see my mistake, because I just can't find it.

I have a simple storyboard-based application I just started. The initial ViewController is an instance of UITabBarController with the two dummy ViewControllers from the template. Upon start up I need to check if the device is logged into an external service. If not I will show a modal ViewController that will allow the user to authenticate, if the device is authenticated then I will just show the FirstViewController.

The following steps are everything I have done since creating the project:

  1. Create the AuthenticateViewController scene on the Storyboard
  2. Create code files for AuthenticateViewController, and assign them to the corresponding scene
  3. Create code files for a UITabBarController subclass, and associate the initial UITabBarController scene to that new subclass
  4. Create a new segue on the storyboard from the UITabBarController scene to the AuthenticateViewController scene
  5. Manually call the segue from viewDidLoad in the UITabBarController subclass

When I run the application the modal segue does not fire, the first ViewController of the UITabBarController is shown, and I get the following output in XCode:

Warning: Attempt to present <AuthenticateViewController: 0x83c0c10> on <EPTabBarController: 0x83be600> whose view is not in the window hierarchy!

Relevant code below, in fact the only code I have added so far. Please let me know if screenshots or additional information would be useful. Thanks in advance for your help.

EPTabBarController, subclass of UITabBarController:

#import "EPTabBarController.h"
#import "AuthenticateViewController.h"

@interface EPTabBarController ()

@end

@implementation EPTabBarController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self performSegueWithIdentifier:@"authenticationSegue" sender:self];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Upvotes: 10

Views: 9049

Answers (3)

Rhuantavan
Rhuantavan

Reputation: 445

How about simply calling your code in viewDidAppear?

- (void)viewDidAppear
{
    [super viewDidAppear];    
    [self performSegueWithIdentifier:@"authenticationSegue" sender:self];
}

However, I am still unsatisfied of these solutions because the original view still shows up for a fraction of a second.

Any idea on how to show the new modal without showing the original view first?

Upvotes: 3

βhargavḯ
βhargavḯ

Reputation: 9836

The issue is inside

- (void)viewDidLoad
{
    [super viewDidLoad];    
    [self performSegueWithIdentifier:@"authenticationSegue" sender:self];
}

you are trying to present another view( AuthenticateViewController ) while your current view( EPTabBarController ) is not yet loaded in the window hierarchy.

So first let your EPTabBarController to get loaded in window hierarchy and then present AuthenticateViewController.

Give this a try

- (void)viewDidLoad 
{
    [super viewDidLoad];        
    [self performSelector:@selector(loadAuthenticateViewController) 
               withObject:nil 
               afterDelay:1.0];
}

-(void)loadAuthenticateViewController 
{
    [self performSegueWithIdentifier:@"authenticationSegue" sender:self];
}

Upvotes: 14

max
max

Reputation: 30043

When you really want to be in control, use something like this:

@implementation UeInitialisationViewController
BOOL didLoad;
BOOL wantPush;

- (id)init {
    self = [super init];
    if (self) { didLoad = NO; wantPush = NO; }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    didLoad = YES;
    if (wantPush == YES)
        [self performSelector:@selector(pushToMainView) 
                   withObject:nil afterDelay:0.0001];
}

- (void)pushToMainView {
    if (didLoad == YES)
        [self performSegueWithIdentifier:@"pushToMainView" sender:self];
    else
        wantPush = YES;
}
@end

This will fire the Segue pushToMainViewwhen you message [controller pushToMainView] but holds back, until the view is loaded.

Upvotes: 2

Related Questions