Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

selecting alternative first view controller from story board at application startup

I've just started on iOS programming and so far the tutorials and answers I found here have been a great help to move forward. However, this particular problem has been bumming me all night and I can't find an answer that "feels right".

I'm writing an application that connects to a remote service and the users need to sign in before they can use it. When they start using the application, their first view should be the sign in dialog; when they've authenticated before, they immediately see the overview page.

The project uses story boards - which I think is a great feature - so most of the code that selects and loads the root view controller is already taken care of. I thought the best place to add my logic is the application:didFinishLaunchingWithOptions: method of the AppDelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
      (NSDictionary *)launchOptions
{
    // select my root view controller here based on credentials present or not
    return YES;
}

But this brought up two questions:

  1. Inside this particular delegate method, the root view controller has already been selected (and loaded?) based on the story board. Could I move to an earlier spot in the loading process to override the first view controller selection or would that needlessly complicate matters?

  2. To override the first view controller I need a reference to the story board, but I couldn't find a better way than to use the storyboardWithName:bundle: constructor of UIStoryboard. That feels wrong, the application should already have a reference to the story board, but how can I access it?

Update

I worked out the second issue I was having, as I found my answer here:

UIStoryboard: What's the Correct Way to Get the Active Storyboard?

NSBundle *bundle = [NSBundle mainBundle];
NSString *sbFile = [bundle objectForInfoDictionaryKey:@"UIMainStoryboardFile"];
UIStoryboard *sb = [UIStoryboard storyboardWithName:sbFile bundle:bundle];

The above will create a new story board instance; to get the active instance, it's a whole lot simpler:

UIStoryboard *sb = [[self.window rootViewController] storyboard];

In the story board file itself you have to set an identifier for the view you wish to load, e.g. LoginDialog. Afterwards you instantiate the view like this:

LoginViewController *login = [sb instantiateViewControllerWithIdentifier:@"LoginDialog"];
[self.window setRootViewController:login];

Within another view controller, the following suffices:

UIStoryboard *sb = self.storyboard;
LoginViewController *login = [sb instantiateViewControllerWithIdentifier:@"LoginDialog"];
[self presentViewController:login animated:NO completion:nil];
like image 245
Ja͢ck Avatar asked May 31 '12 03:05

Ja͢ck


People also ask

How do I change the initial view controller in storyboard?

Specifying the Initial View Controllerstoryboard and select the Tab Bar Controller Scene. On the right, select the Attribute inspector. You'll find a checkbox named Is Initial View Controller. Checking this box will identify the selected view controller as the initial entry point for the storyboard you're on.


2 Answers

You can just reset the root view controller of the window

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
      (NSDictionary *)launchOptions
{
   if(your_condition) {
       UIViewController *newRoot = [your implementation];
       self.window.rootViewController = newRoot;
   }
   return YES;
}

This is worked for me, Xcode5.0.1

like image 59
Danyun Liu Avatar answered Sep 19 '22 05:09

Danyun Liu


I have a similar scenario as yours. My application uses a UINavigationController as the root view controller. If the user is logged in, I want to present him/her with NotLoggedInViewController, while if it's logged in I want to show the LoggedInViewController.

In a storyboard a UINavigationController can only have one child, so you have to be able to programmatically assign another root view controller to it.

I start by creating a custom navigation controller class, let's name it MyNavigationController. In the storyboard I assign this custom class to the navigation controller object.

Still in the storyboard, I then model both view controllers, and connect one of them to the navigation controller object. Since I need to be able to access them from my code later on, I assign each of them an identifier using the XCode inspector on the right. These identifiers which can be arbitrary strings, but to things simple I just use the class names.

Finally I then implement the viewDidLoad method on MyNavigationController class:

BOOL isLoggedIn = ...;

- (void)viewDidLoad {
  id rootController;
  if (isLoggedIn) {
    rootController = [self.storyboard instantiateViewControllerWithIdentifier:@"LoggedInViewController"];
  } else {
    rootController = [self.storyboard instantiateViewControllerWithIdentifier:@"NotLoggedInViewController"];
  }
  self.viewControllers = [NSArray arrayWithObjects:rootController, nil];
}
like image 36
ovidiu Avatar answered Sep 18 '22 05:09

ovidiu