有条件地从AppDelegate开始在故事板中的不同位置

mmv*_*vie 107 objective-c storyboard uiapplicationdelegate segue

我有一个设置有工作登录和主视图控制器的故事板,后者是用户在登录成功时导航到的视图控制器.我的目标是在验证(存储在钥匙串中)成功时立即显示主视图控制器,如果验证失败则显示登录视图控制器.基本上,我想在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
}
Run Code Online (Sandbox Code Playgroud)

我知道方法performSegueWithIdentifier:但是这个方法是UIViewController的实例方法,所以不能从AppDelegate中调用.如何使用我现有的故事板来做到这一点?

编辑:

故事板的初始视图控制器现在是一个没有连接任何东西的导航控制器.我使用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;
}
Run Code Online (Sandbox Code Playgroud)

欢迎提出建议/改进!

fol*_*ben 169

我对这里建议的一些解决方案感到惊讶.

您的故事板中确实不需要虚拟导航控制器,隐藏视图并在viewDidAppear上触发segue:或任何其他黑客攻击.

如果您没有在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;
}
Run Code Online (Sandbox Code Playgroud)

如果故事板在应用程序的配置的plist,窗口和根视图控制器将已经由时间应用程序设置: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;
}
Run Code Online (Sandbox Code Playgroud)


rob*_*off 25

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

我还假设故事板中的初始视图控制器是导航控制器,您要在其上推送主视图控制器或登录视图控制器.

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

NSString *segueId = success ? @"pushMain" : @"pushLogin";
[self.window.rootViewController performSegueWithIdentifier:segueId sender:self];
Run Code Online (Sandbox Code Playgroud)

  • 是的,也不适合我.为什么你标记它答案如果它对你不起作用? (3认同)
  • 我相信这是正确的答案.你需要1.在你的app委托上有一个window属性,然后在应用程序中调用`[[self window] makeKeyAndVisible]`:didFinishLaunchingWithOptions:在你尝试执行条件segues之前.UIApplicationMain()假设消息makeKeyAndVisible,但只在didFinish之后才这样做...选项:完成.有关详细信息,请查看Apple文档中的"在视图控制器之间协调工作". (3认同)

Raz*_*van 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;
}
Run Code Online (Sandbox Code Playgroud)

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

//IF YOU DON'T USE A NAVIGATION CONTROLLER:
[self.window setRootViewController:presentedViewController];
Run Code Online (Sandbox Code Playgroud)

有:

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


Mat*_*ick 9

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

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

替换YourStartingViewController为您实际的第一个视图控制器类的名称(您不希望出现的YourSegueIdentifier那个)的名称,以及该启动控制器与您想要实际启动的控制器之间的segue的实际名称(segue之后的名称) ).

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


Ric*_*aca 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;
}
Run Code Online (Sandbox Code Playgroud)

传递给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;
}
Run Code Online (Sandbox Code Playgroud)