web-dev-qa-db-fra.com

Commencer conditionnellement à différents endroits du storyboard à partir d'AppDelegate

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!

107
mmvie

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];
25
rob mayoff

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

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];
18
Razvan

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.

9
Matthew Frederick

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:

enter image description here

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;
}
6
Rich Apodaca

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.

4
Darren

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

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;
}
1
Luc Bloom

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

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. :)

0
thanhbinh84