J'ai un storyboard configuré avec une connexion de travail et un contrôleur de vue principal, ce dernier est le contrôleur de vue vers lequel l'utilisateur est dirigé lorsque la connexion est réussie. Mon objectif est d’afficher immédiatement le contrôleur de vue principal si l’authentification (stockée dans le trousseau) est réussie et d’afficher le contrôleur de vue de connexion si l’authentification a échoué. En gros, je veux faire cela dans mon 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
}
Je connais la méthode performSegueWithIdentifier: mais cette méthode est une méthode d'instance de UIViewController, elle ne peut donc pas être appelée à partir d'AppDelegate. Comment puis-je faire cela en utilisant mon storyboard existant?
MODIFIER:
Le contrôleur de vue initial du Storyboard est maintenant un contrôleur de navigation qui n'est connecté à rien. J'ai utilisé le setRootViewController: distinction parce que MainIdentifier est un UITabBarController. Ensuite, voici à quoi ressemblent mes lignes:
- (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;
}
Les suggestions/améliorations sont les bienvenues!
Je suppose que votre storyboard est défini comme le "storyboard principal" (touche UIMainStoryboardFile
dans votre Info.plist). Dans ce cas, UIKit chargera le storyboard et définira son contrôleur de vue initial en tant que contrôleur de vue racine de votre fenêtre avant l'envoi de application:didFinishLaunchingWithOptions:
à votre AppDelegate.
Je suppose également que le contrôleur de vue initial de votre storyboard est le contrôleur de navigation sur lequel vous souhaitez pousser votre contrôleur de vue principal ou de connexion.
Vous pouvez demander à votre fenêtre son contrôleur de vue racine et envoyer le fichier performSegueWithIdentifier:sender:
message à ce sujet:
NSString *segueId = success ? @"pushMain" : @"pushLogin";
[self.window.rootViewController performSegueWithIdentifier:segueId sender:self];
Je suis surpris de certaines des solutions proposées ici.
Il n'y a vraiment pas besoin de contrôleurs de navigation factices dans votre story-board, masquant les vues et les séquences de tir sur viewDidAppear: ni aucun autre piratage.
Si le storyboard n'est pas configuré dans votre fichier plist, vous devez créer vous-même la fenêtre et le contrôleur de vue racine :
- (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;
}
Si le storyboard est configuré dans le plist de l'application, les contrôleurs de vue de la fenêtre et de la racine seront déjà configurés à l'application suivante: didFinishLaunching: est appelée et makeKeyAndVisible. sera appelé sur la fenêtre pour vous.
Dans ce cas, c'est encore plus simple:
- (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;
}
SI le point d’entrée de votre storyboard n’est pas un 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;
}
SI le point d’entrée de votre storyboard IS an UINavigationController
remplace:
//IF YOU DON'T USE A NAVIGATION CONTROLLER:
[self.window setRootViewController:presentedViewController];
avec:
//IF YOU USE A NAVIGATION CONTROLLER AS THE ENTRY POINT IN YOUR STORYBOARD:
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController pushViewController:presentedViewController animated:NO];
Dans votre AppDelegate's application:didFinishLaunchingWithOptions
méthode, avant le return YES
ligne, ajouter:
UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
YourStartingViewController *yourStartingViewController = [[navigationController viewControllers] objectAtIndex:0];
[yourStartingViewController performSegueWithIdentifier:@"YourSegueIdentifier" sender:self];
Remplacez YourStartingViewController
par le nom de votre première classe de contrôleur de vue (celle que vous ne voulez pas forcément apparaître) et YourSegueIdentifier
par le nom réel de la transition entre ce contrôleur de départ et celui vous voulez réellement commencer (celui après la transition).
Enveloppez ce code dans une conditionnelle if
si vous ne voulez pas toujours que cela se produise.
Etant donné que vous utilisez déjà un Storyboard, vous pouvez l’utiliser pour présenter à l’utilisateur MyViewController, un contrôleur personnalisé (Boiling down followben's answer un peu).
Dans 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;
}
La chaîne transmise à instantiateViewControllerWithIdentifier fait référence à l'ID de storyboard, qui peut être défini dans le générateur d'interface:
Enveloppez cela dans la logique si nécessaire.
Si vous commencez avec un UINavigationController, cependant, cette approche ne vous donnera pas de contrôle de navigation.
Pour "avancer" depuis le point de départ d'un contrôleur de navigation configuré via le constructeur d'interface, utilisez cette approche:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navigation = (UINavigationController *) self.window.rootViewController;
[navigation.visibleViewController performSegueWithIdentifier:@"my-named-segue" sender:nil];
return YES;
}
Pourquoi ne pas avoir l'écran de connexion qui apparaît en premier, vérifier si l'utilisateur est déjà connecté et pousser immédiatement l'écran suivant? Tout dans le ViewDidLoad.
Mise en œuvre rapide de la même chose:
Si vous utilisez UINavigationController
comme point d’entrée dans le 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)
}
C’est la solution qui a fonctionné sur iOS7. Pour accélérer le chargement initial et éviter tout chargement inutile, j'ai un contrôleur UIView complètement vide appelé "DUMMY" dans mon fichier Storyboard. Ensuite, je peux utiliser le code suivant:
- (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;
}
Après avoir essayé différentes méthodes, j'ai pu résoudre ce problème avec ceci:
-(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;
}
Je suggère de créer un nouveau MainViewController qui soit le contrôleur de vue racine du contrôleur de navigation. Pour ce faire, maintenez simplement le contrôle, puis faites glisser la connexion entre le contrôleur de navigation et MainViewController, choisissez "Relation - Contrôleur de vue racine" dans Invite.
Dans MainViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
if (isLoggedIn) {
[self performSegueWithIdentifier:@"HomeSegue" sender:nil];
} else {
[self performSegueWithIdentifier:@"LoginSegue" sender:nil];
}
}
N'oubliez pas de créer des séparations entre MainViewController avec les contrôleurs de vue Accueil et Connexion. J'espère que cela t'aides. :)