有条件地从AppDelegate的故事板中的不同位置开始

我有一个设置了工作login和主视图控制器的故事板,后者是login成功时用户导航到的视图控制器。 我的目标是显示主视图控制器立即如果authentication(存储在keychain)成功,并显示login视图控制器,如果authentication失败。 基本上,我想在我的AppDelegate中做到这一点:

// 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的一个实例方法,所以不能从AppDelegate中调用。 我如何使用我现有的故事板做到这一点?

编辑:

故事板的初始视图控制器现在是一个没有连接任何东西的导航控制器。 我使用了setRootViewController:区别,因为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; } 

build议/改进,欢迎!

我假设你的故事板被设置为“主要故事板”(你的Info.plist中的关键UIMainStoryboardFile )。 在这种情况下,UIKit将加载故事板,并将其初始视图控制器设置为窗口的根视图控制器,然后将application:didFinishLaunchingWithOptions:发送到您的AppDelegate。

我还假设故事板中的初始视图控制器是导航控制器,您要将其推送到您的主视图控制器或login视图控制器。

你可以问你的窗口的根视图控制器,并发送performSegueWithIdentifier:sender:消息:

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

我对这里提出的一些解决scheme感到惊讶。

真的不需要你的故事板上的虚拟导航控制器,隐藏viewDidAppear:或任何其他黑客的视图和解雇赛。

如果您没有在plist文件中configuration故事板,则必须自己创build窗口和根视图控制器 :

 - (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; } 

如果故事板在应用程序的plist中configuration的,则窗口和根视图控制器将已经由时间应用程序设置:didFinishLaunching:被调用,并且makeKeyAndVisible将在窗口上为您调用。

在这种情况下,它更简单:

 - (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; } 

如果您的故事板的入口点不是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; } 

如果你的故事板的入口点是一个UINavigationControllerreplace:

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

有:

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

在您的AppDelegate application:didFinishLaunchingWithOptions方法,在return YES行之前,添加:

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

YourStartingViewControllerreplace为实际的第一个视图控制器类(不想出现的那个控制器类)的名称和YourSegueIdentifier ,并在起始控制器和实际启动的控制器之间赛格)。

如果你不总是希望它发生的if把这个代码包装在if条件中。

假设你已经使用了一个Storyboard,你可以使用这个来向用户提供MyViewController,一个自定义的控制器(沸腾了followben的答案 )。

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; } 

传递给instantiateViewControllerWithIdentifier的string指的是可以在界面构build器中设置的Storyboard ID:

在这里输入图像描述

只需按需要将其包装在逻辑中即可。

如果你从一个UINavigationController开始,这种方法不会给你导航控件。

要从通过界面生成器设置的导航控制器的起始点“跳跃”,请使用以下方法:

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { UINavigationController *navigation = (UINavigationController *) self.window.rootViewController; [navigation.visibleViewController performSegueWithIdentifier:@"my-named-segue" sender:nil]; return YES; } 

为什么不让login屏幕先出现,检查用户是否已经login,并立即推入下一个屏幕? 全部在ViewDidLoad中。

快速实施:

如果您使用UINavigationController作为故事板中的入口点

 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) } 

这是在iOS7下工作的解决scheme。 为了加速初始加载,不做任何不必要的加载,我有一个完全空的UIViewcontroller在我的故事板文件中称为“DUMMY”。 然后我可以使用下面的代码:

 - (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; } 

我build议创build一个新的MainViewController,它是导航控制器的根视图控制器。 要做到这一点,只要保持控制,然后拖动导航控制器和MainViewController之间的连接,从提示中select“关系 – 根视图控制器”。

在MainViewController中:

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

请记住在MainViewController与Home和Login视图控制器之间创build一个Segges。 希望这可以帮助。 🙂

尝试了很多不同的方法后,我可以用这个解决这个问题:

 -(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; }