107

我有一个带有工作登录和主视图控制器的故事板,后者是登录成功时用户导航到的视图控制器。我的目标是如果身份验证(存储在钥匙串中)成功则立即显示主视图控制器,如果身份验证失败则显示登录视图控制器。基本上,我想在我的 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 中调用。如何使用我现有的故事板做到这一点?

编辑:

Storyboard 的初始视图控制器现在是一个导航控制器,它没有连接到任何东西。我使用了 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;
}

欢迎提出建议/改进!

4

10 回答 10

170

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

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

如果您没有在 plist 文件中配置情节提要,则必须自己创建窗口和根视图控制器

- (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配置了故事板,则窗口和根视图控制器将在 application: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;
}
于 2012-10-09T11:53:04.430 回答
25

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

我还假设情节提要中的初始视图控制器是导航控制器,您希望将主视图控制器或登录视图控制器推送到该控制器上。

您可以向您的窗口询问其根视图控制器,并将performSegueWithIdentifier:sender:消息发送给它:

NSString *segueId = success ? @"pushMain" : @"pushLogin";
[self.window.rootViewController performSegueWithIdentifier:segueId sender:self];
于 2011-12-10T09:05:31.530 回答
18

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

如果您的故事板的入口点是UINavigationController替换:

//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];
于 2012-09-02T13:02:56.750 回答
10

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

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

替换YourStartingViewController为您的实际第一个视图控制器类的名称(您不想出现的那个)以及YourSegueIdentifier该起始控制器和您要实际开始的控制器之间的实际名称(segue 之后的那个) )。

if如果您不总是希望它发生,则将该代码包装在条件中。

于 2012-07-10T20:44:09.570 回答
6

鉴于您已经在使用 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 的字符串是指 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;
}
于 2012-10-23T23:00:50.777 回答
4

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

于 2011-12-12T22:17:38.617 回答
3

快速实现相同:

如果您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) 
    }
于 2016-01-03T12:54:50.140 回答
1

这是适用于 iOS7 的解决方案。为了加快初始加载并且不进行任何不必要的加载,我的 Storyboard 文件中有一个名为“DUMMY”的完全空的 UIViewcontroller。然后我可以使用以下代码:

- (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;
}
于 2013-09-26T11:36:50.753 回答
0

我建议创建一个新的 MainViewController,它是 Navigation Controller 的 Root View Controller。为此,只需按住控件,然后拖动 Navigation Controller 和 MainViewController 之间的连接,从提示中选择“Relationship - Root View Controller”。

在 MainViewController 中:

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

请记住在 MainViewController 与 Home 和 Login 视图控制器之间创建 segues。希望这可以帮助。:)

于 2012-07-26T07:31:19.920 回答
0

在尝试了许多不同的方法之后,我能够用这个来解决这个问题:

-(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;
}
于 2012-09-02T15:13:11.923 回答