有条件地从应用委托的故事板中的不同位置开始

我用工作登录和主视图控制器设置了一个情节串连板,后者是登录成功时用户导航到的视图控制器。 我的目标是在身份验证成功时立即显示主视图控制器(存储在密钥链中) ,并在身份验证失败时显示登录视图控制器。 基本上,我想在我的应用程序代理中这样做:

// url request & response work fine, assume success is a BOOL here
// that indicates whether login was successful or not


if (success) {
// 'push' main view controller
} else {
// 'push' login view controller
}

我知道这个方法 PerformSegueWithIdentifier: 但是这个方法是 UIViewController 的一个实例方法,所以不能从 Appete 内部调用。 我如何使用我现有的故事板来做到这一点? ?

编辑:

Storyboard 的初始视图控制器现在是一个没有连接到任何东西的导航控制器。我使用 setRootViewController: different 是因为 MainIdentifier 是一个 UITabBarController。我的台词是这样的:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isLoggedIn = ...;    // got from server response


NSString *segueId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:segueId];


if (isLoggedIn) {
[self.window setRootViewController:initViewController];
} else {
[(UINavigationController *)self.window.rootViewController pushViewController:initViewController animated:NO];
}


return YES;
}

欢迎提供意见/改善建议!

50930 次浏览

I assume your storyboard is set as the "main storyboard" (key UIMainStoryboardFile in your Info.plist). In that case, UIKit will load the storyboard and set its initial view controller as your window's root view controller before it sends application:didFinishLaunchingWithOptions: to your AppDelegate.

I also assume that the initial view controller in your storyboard is the navigation controller, onto which you want to push your main or login view controller.

You can ask your window for its root view controller, and send the performSegueWithIdentifier:sender: message to it:

NSString *segueId = success ? @"pushMain" : @"pushLogin";
[self.window.rootViewController performSegueWithIdentifier:segueId sender:self];

Why not have the login screen which appears first, check if the user is already logged in and push the next screen straight away? All in the ViewDidLoad.

In your AppDelegate's application:didFinishLaunchingWithOptions method, before the return YES line, add:

UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
YourStartingViewController *yourStartingViewController = [[navigationController viewControllers] objectAtIndex:0];
[yourStartingViewController performSegueWithIdentifier:@"YourSegueIdentifier" sender:self];

Replace YourStartingViewController with the name of your actual first view controller class (the one you don't want to necessarily appear) and YourSegueIdentifier with the actual name of the segue between that starting controller and the one you want to actually start on (the one after the segue).

Wrap that code in an if conditional if you don't always want it to happen.

I suggest to create a new MainViewController that is Root View Controller of Navigation Controller. To do that, just hold control, then drag connection between Navigation Controller and MainViewController, choose 'Relationship - Root View Controller' from prompt.

In MainViewController:

- (void)viewDidLoad
{
[super viewDidLoad];
if (isLoggedIn) {
[self performSegueWithIdentifier:@"HomeSegue" sender:nil];
} else {
[self performSegueWithIdentifier:@"LoginSegue" sender:nil];
}
}

Remember to create segues between MainViewController with Home and Login view controllers. Hope this helps. :)

IF your storyboard's entry point isn't an UINavigationController:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {




//Your View Controller Identifiers defined in Interface Builder
NSString *firstViewControllerIdentifier  = @"LoginViewController";
NSString *secondViewControllerIdentifier = @"MainMenuViewController";


//check if the key exists and its value
BOOL appHasLaunchedOnce = [[NSUserDefaults standardUserDefaults] boolForKey:@"appHasLaunchedOnce"];


//if the key doesn't exist or its value is NO
if (!appHasLaunchedOnce) {
//set its value to YES
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"appHasLaunchedOnce"];
[[NSUserDefaults standardUserDefaults] synchronize];
}


//check which view controller identifier should be used
NSString *viewControllerIdentifier = appHasLaunchedOnce ? secondViewControllerIdentifier : firstViewControllerIdentifier;


//IF THE STORYBOARD EXISTS IN YOUR INFO.PLIST FILE AND YOU USE A SINGLE STORYBOARD
UIStoryboard *storyboard = self.window.rootViewController.storyboard;


//IF THE STORYBOARD DOESN'T EXIST IN YOUR INFO.PLIST FILE OR IF YOU USE MULTIPLE STORYBOARDS
//UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"YOUR_STORYBOARD_FILE_NAME" bundle:nil];


//instantiate the view controller
UIViewController *presentedViewController = [storyboard instantiateViewControllerWithIdentifier:viewControllerIdentifier];


//IF YOU DON'T USE A NAVIGATION CONTROLLER:
[self.window setRootViewController:presentedViewController];


return YES;
}

IF your storyboard's entry point IS an UINavigationController replace:

//IF YOU DON'T USE A NAVIGATION CONTROLLER:
[self.window setRootViewController:presentedViewController];

with:

//IF YOU USE A NAVIGATION CONTROLLER AS THE ENTRY POINT IN YOUR STORYBOARD:
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController pushViewController:presentedViewController animated:NO];

After trying many different methods, I was able to solve this problem with this:

-(void)viewWillAppear:(BOOL)animated {


// Check if user is already logged in
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
if ([[prefs objectForKey:@"log"] intValue] == 1) {
self.view.hidden = YES;
}
}


-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];


// Check if user is already logged in
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
if ([[prefs objectForKey:@"log"] intValue] == 1) {
[self performSegueWithIdentifier:@"homeSeg3" sender:self];
}
}


-(void)viewDidUnload {
self.view.hidden = NO;
}

I'm surprised at some of the solutions being suggested here.

There's really no need for dummy navigation controllers in your storyboard, hiding views & firing segues on viewDidAppear: or any other hacks.

If you don't have the storyboard configured in your plist file, you must create both the window and the root view controller yourself :

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isLoggedIn = ...;    // from your server response


NSString *storyboardId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:storyboardId];


self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = initViewController;
[self.window makeKeyAndVisible];


return YES;
}

If the storyboard is configured in the app's plist, the window and root view controller will already be setup by the time application:didFinishLaunching: is called, and makeKeyAndVisible will be called on the window for you.

In that case, it's even simpler:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isLoggedIn = ...;    // from your server response


NSString *storyboardId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardId];


return YES;
}

Given that you're already using a Storyboard, you can use this to present the user with MyViewController, a custom controller (Boiling down followben's answer a bit).

In AppDelegate.m:

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
MyCustomViewController *controller = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"MyCustomViewController"];


// now configure the controller with a model, etc.


self.window.rootViewController = controller;


return YES;
}

The string passed to instantiateViewControllerWithIdentifier refers to the Storyboard ID, which can be set in interface builder:

enter image description here

Just wrap this in logic as needed.

If you're starting with a UINavigationController, though, this approach will not give you navigation controls.

To 'jump forward' from the starting point of a navigation controller set up through interface builder, use this approach:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navigation = (UINavigationController *) self.window.rootViewController;


[navigation.visibleViewController performSegueWithIdentifier:@"my-named-segue" sender:nil];


return YES;
}

This is the solution that worked n iOS7. To speed up the initial loading and not do any unnecessary loading, I have a completely empty UIViewcontroller called "DUMMY" in my Storyboard file. Then I can use the following code:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];


NSString* controllerId = @"Publications";
if (![NSUserDefaults.standardUserDefaults boolForKey:@"hasSeenIntroduction"])
{
controllerId = @"Introduction";
}
else if (![NSUserDefaults.standardUserDefaults boolForKey:@"hasDonePersonalizationOrLogin"])
{
controllerId = @"PersonalizeIntro";
}


if ([AppDelegate isLuc])
{
controllerId = @"LoginStart";
}


if ([AppDelegate isBart] || [AppDelegate isBartiPhone4])
{
controllerId = @"Publications";
}


UIViewController* controller = [storyboard instantiateViewControllerWithIdentifier:controllerId];
self.window.rootViewController = controller;


return YES;
}

Swift implementation of same :

If you use UINavigationController as entry point in storyboard

let storyboard = UIStoryboard(name: "Main", bundle: nil)


var rootViewController = self.window!.rootViewController as! UINavigationController;


if(loginCondition == true){


let profileController = storyboard.instantiateViewControllerWithIdentifier("ProfileController") as? ProfileController
rootViewController.pushViewController(profileController!, animated: true)
}
else {


let loginController =   storyboard.instantiateViewControllerWithIdentifier("LoginController") as? LoginController
rootViewController.pushViewController(loginController!, animated: true)
}