107 votes

Conditionnellement commencer à différents endroits dans le storyboard à partir de AppDelegate

J'ai un storyboard set up avec login et principale-vue-contrôleur, ce dernier est le point de vue du contrôleur à l'utilisateur de naviguer à quand la connexion est réussie. Mon objectif est de montrer à l'écran principal contrôleur immédiatement si l'authentification (stockées dans le trousseau d'accès) est couronnée de succès, et de montrer la connexion view controller si l'authentification a échoué. En gros, je veux faire 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 sais à propos de la méthode performSegueWithIdentifier: mais cette méthode est une méthode d'instance de UIViewController, afin de ne pas être appelé à partir à l'intérieur de AppDelegate. Comment dois-je faire cela à l'aide de mon storyboard ??

EDIT:

Le Storyboard point de vue initial du contrôleur est maintenant une manette de navigation qui n'est pas relié à quoi que ce soit. J'ai utilisé le setRootViewController: distinction parce que MainIdentifier est un UITabBarController. Alors c'est ce que mes lignes de ressembler à:

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

Suggestions/améliorations sont les bienvenues!

169voto

followben Points 3073

Je suis surpris de voir certaines des solutions proposées.

Il n'y a vraiment pas besoin de mannequin manettes de navigation dans votre storyboard, se cachant de vues et de tir enchaîne sur viewDidAppear: ou toutes autres hacks.

Si vous n'avez pas le storyboard configuré dans votre fichier plist, vous devez créer la fenêtre et la vue racine contrôleur de vous-même :

- (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 l'application de la plist, la fenêtre et la vue de la racine contrôleur sera déjà de configuration par l'application d':didFinishLaunching: est appelé, et makeKeyAndVisible sera appelée 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;
}

25voto

rob mayoff Points 124153

Je suppose que votre scénario est défini comme le "storyboard" (touche UIMainStoryboardFile de votre Info.plist). Dans ce cas, UIKit va charger la table de montage séquentiel et de définir son point de vue initial du contrôleur de votre fenêtre de la vue racine contrôleur avant qu'il envoie application:didFinishLaunchingWithOptions: de votre AppDelegate.

J'ai également supposer que le point de vue initial du contrôleur dans votre storyboard est la manette de navigation, sur lequel vous voulez pousser votre principal ou de connexion view controller.

Vous pouvez demander à votre fenêtre pour sa racine-vue-contrôleur, et d'envoyer l' performSegueWithIdentifier:sender: message:

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

18voto

codeFi Points 858

Viens de tester le code suivant dans mon app - appDelegate.h. (J'ai une première - première application utilisez - vue-contrôleur et l'un des principaux view controller qui est instancié après le premier lancement de l'application). Donc, si vous utilisez un UINavigationController vous devriez utiliser quelque chose comme ce qui suit (le point de vue doit être poussé):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if ([[NSUserDefaults standardUserDefaults] boolForKey:@"HasLaunchedOnce"])
    {
        // app already launched once
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
        MainViewController *mvc = [storyboard instantiateViewControllerWithIdentifier:@"MVC"];
        [(UINavigationController*)self.window.rootViewController pushViewController:mvc animated:NO];
        NSLog(@"Already Launched");
    }
    else
    {
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"HasLaunchedOnce"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        // This is the first launch ever
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
        InitialUseViewController *ivc = [storyboard instantiateViewControllerWithIdentifier:@"IVC"];
        [(UINavigationController*)self.window.rootViewController pushViewController:ivc animated:NO];
        NSLog(@"First Launch");
    }

    return YES;
}

9voto

Matthew Frederick Points 14932

Dans votre AppDelegate de l' application:didFinishLaunchingWithOptions méthode, avant de l' return YES de la ligne, ajouter:

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

Remplacer YourStartingViewController avec le nom de votre premier point de vue de la classe contrôleur (celui que vous ne voulez pas nécessairement apparaître) et YourSegueIdentifier par le nom réel de la séquence entre que contrôleur de départ et celle que vous voulez à réellement démarrer sur (l'un après l'segue).

Envelopper ce code dans un if conditionnelle si vous n'avez pas toujours envie de se produire.

4voto

Darren Points 3714

Pourquoi ne pas avoir l'écran de connexion qui s'affiche en premier, vérifier si l'utilisateur est déjà connecté et de pousser l'écran suivant tout de suite? Tous dans le ViewDidLoad.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X