Começar condicionalmente em lugares diferentes no storyboard do AppDelegate

Eu tenho um storyboard configurado com login de trabalho e controlador de visualização principal, o último é o controlador de visualização para o qual o usuário é navegado quando o login é bem-sucedido. Meu objective é mostrar o controlador de visualização principal imediatamente se a autenticação (armazenada no keychain) for bem-sucedida e mostrar o controlador de visualização de login se a autenticação falhar. Basicamente, eu quero fazer isso no meu 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 } 

Eu sei sobre o método performSegueWithIdentifier: mas esse método é um método de instância do UIViewController, portanto, não pode ser chamado a partir do AppDelegate. Como faço isso usando meu storyboard existente?

EDITAR:

O controlador de visualização inicial do Storyboard agora é um controlador de navegação que não está conectado a nada. Eu usei o setRootViewController: distinção porque MainIdentifier é um UITabBarController. Então é assim que minhas linhas se parecem:

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

Sugestões / melhorias são bem vindas!

Presumo que seu storyboard esteja definido como o “storyboard principal” (chave UIMainStoryboardFile em seu Info.plist). Nesse caso, o UIKit carregará o storyboard e configurará seu controlador de visualização inicial como o controlador de visualização raiz da janela antes de enviar o application:didFinishLaunchingWithOptions: para o AppDelegate.

Eu também suponho que o controlador de visualização inicial em seu storyboard é o controlador de navegação, no qual você quer empurrar seu controlador de visualização principal ou de login.

Você pode perguntar à sua janela por seu controlador de visualização raiz e enviar a mensagem performSegueWithIdentifier:sender: para ele:

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

Estou surpreso com algumas das soluções sugeridas aqui.

Não há realmente nenhuma necessidade para controladores de navegação fictícios em seu storyboard, ocultando views e dispares em viewDidAppear: ou qualquer outro hacker.

Se você não tiver o storyboard configurado em seu arquivo plist, deverá criar a janela e o controlador de visualização raiz :

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

Se o storyboard estiver configurado na plist do aplicativo, a janela e o controlador de visualização root já estarão configurados pelo aplicativo de horário: didFinishLaunching: é chamado e makeKeyAndVisible será chamado na janela para você.

Nesse caso, é ainda mais simples:

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

Se o ponto de input do seu storyboard não for um 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; } 

SE o ponto de input do seu storyboard for uma substituição do UINavigationController :

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

com:

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

Na application:didFinishLaunchingWithOptions do seu AppDelegate application:didFinishLaunchingWithOptions método application:didFinishLaunchingWithOptions , antes da linha de return YES , adicione:

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

Substitua YourStartingViewController pelo nome da sua primeira class real de view controller (aquela que você não quer que apareça necessariamente) e YourSegueIdentifier com o nome real do segue entre o controlador de partida e o que você quer realmente iniciar (aquele após o segue).

Embrulhe esse código em um if condicional se você nem sempre quiser que isso aconteça.

Dado que você já está usando um Storyboard, você pode usar isso para apresentar o usuário com MyViewController, um controlador personalizado (fervendo abaixo resposta do followben um pouco).

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

A cadeia transmitida para instantiateViewControllerWithIdentifier se refere ao ID do Storyboard, que pode ser configurado no construtor de interface:

insira a descrição da imagem aqui

Apenas envolva isso na lógica conforme necessário.

Se você está começando com um UINavigationController, essa abordagem não fornecerá controles de navegação.

Para “avançar” do ponto de partida de um controlador de navegação configurado pelo construtor de interface, use esta abordagem:

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

Por que não ter a canvas de login que aparece primeiro, verifique se o usuário já está logado e pressione a próxima canvas imediatamente? Tudo no ViewDidLoad.

Implementação rápida do mesmo:

Se você usar o UINavigationController como ponto de input no 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) } 

Esta é a solução que funcionou no iOS7. Para acelerar o carregamento inicial e não fazer nenhum carregamento desnecessário, eu tenho um UIViewcontroller completamente vazio chamado “DUMMY” no meu arquivo Storyboard. Então eu posso usar o seguinte código:

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

Eu sugiro criar um novo MainViewController que seja o Controlador de Visão Raiz do Controlador de Navegação. Para fazer isso, apenas segure o controle, em seguida, arraste a conexão entre o Controlador de Navegação e o MainViewController, escolha ‘Relacionamento – Controlador de Visão Raiz’ no prompt.

No MainViewController:

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

Lembre-se de criar seguidos entre o MainViewController com controladores de visualização Home e Login. Espero que isto ajude. 🙂

Depois de tentar muitos methods diferentes, consegui resolver este problema com isto:

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