15

我刚刚开始进行 iOS 编程,到目前为止,我在这里找到的教程和答案对前进有很大帮助。然而,这个特殊的问题让我整晚都在烦恼,我找不到“感觉正确”的答案。

我正在编写一个连接到远程服务的应用程序,用户需要先登录才能使用它。当他们开始使用应用程序时,他们的第一个视图应该是登录对话框;当他们之前通过身份验证时,他们会立即看到概览页面。

该项目使用故事板——我认为这是一个很棒的特性——所以大部分选择和加载根视图控制器的代码都已经处理好了。我认为添加逻辑的最佳位置是以下application:didFinishLaunchingWithOptions:方法AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
      (NSDictionary *)launchOptions
{
    // select my root view controller here based on credentials present or not
    return YES;
}

但这带来了两个问题:

  1. 在这个特定的委托方法中,根视图控制器已经根据故事板被选择(并加载?)。我是否可以在加载过程中移到更早的位置以覆盖第一个视图控制器选择,或者这会使事情变得不必要地复杂化?

  2. 要覆盖第一个视图控制器,我需要对故事板的引用,但我找不到比使用storyboardWithName:bundle:. UIStoryboard感觉不对,应用程序应该已经有故事板的引用,但是我怎样才能访问它呢?

更新

我解决了我遇到的第二个问题,因为我在这里找到了答案:

UIStoryboard:获取活动故事板的正确方法是什么?

NSBundle *bundle = [NSBundle mainBundle];
NSString *sbFile = [bundle objectForInfoDictionaryKey:@"UIMainStoryboardFile"];
UIStoryboard *sb = [UIStoryboard storyboardWithName:sbFile bundle:bundle];

以上将创建一个新的故事板实例;要获取活动实例,要简单得多:

UIStoryboard *sb = [[self.window rootViewController] storyboard];

在故事板文件本身中,您必须为要加载的视图设置标识符,例如LoginDialog. 之后,您像这样实例化视图:

LoginViewController *login = [sb instantiateViewControllerWithIdentifier:@"LoginDialog"];
[self.window setRootViewController:login];

在另一个视图控制器中,以下内容就足够了:

UIStoryboard *sb = self.storyboard;
LoginViewController *login = [sb instantiateViewControllerWithIdentifier:@"LoginDialog"];
[self presentViewController:login animated:NO completion:nil];
4

4 回答 4

13

您可以重置窗口的根视图控制器

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
      (NSDictionary *)launchOptions
{
   if(your_condition) {
       UIViewController *newRoot = [your implementation];
       self.window.rootViewController = newRoot;
   }
   return YES;
}

这对我有用,Xcode5.0.1

于 2013-12-03T03:23:52.603 回答
7

我有一个和你类似的场景。我的应用程序使用 aUINavigationController作为根视图控制器。如果用户已登录,我想向他/她展示NotLoggedInViewController,而如果它已登录,我想显示LoggedInViewController.

在情节提要中,aUINavigationController只能有一个孩子,因此您必须能够以编程方式为其分配另一个根视图控制器。

我首先创建一个自定义导航控制器类,我们将其命名为MyNavigationController。在情节提要中,我将此自定义类分配给导航控制器对象。

仍然在情节提要中,然后我对两个视图控制器进行建模,并将其中一个连接到导航控制器对象。由于稍后我需要能够从我的代码中访问它们,因此我使用右侧的 XCode 检查器为它们中的每一个分配了一个标识符。这些标识符可以是任意字符串,但为了简单起见,我只使用类名。

最后,我viewDidLoad在类上实现该方法MyNavigationController

BOOL isLoggedIn = ...;

- (void)viewDidLoad {
  id rootController;
  if (isLoggedIn) {
    rootController = [self.storyboard instantiateViewControllerWithIdentifier:@"LoggedInViewController"];
  } else {
    rootController = [self.storyboard instantiateViewControllerWithIdentifier:@"NotLoggedInViewController"];
  }
  self.viewControllers = [NSArray arrayWithObjects:rootController, nil];
}
于 2012-06-02T06:58:26.100 回答
2

我几乎没有使用故事板,可能这不是您问题的确切答案。但是我会建议您以某种方式在我的项目中所做的工作,而无需使用情节提要。

didFinishLaunchingWithOptions AuthenticationViewController中是加载的第一个视图。它询问登录凭据。输入后,它将输入项目使用的实际 ViewControllers(即 TabBar &all..)。

添加到项目中的有趣功能是,当您输入凭据时,我会弹出一个UIAleretView要求用户选择三个选项之一的选项。

  1. 无需密码即可保存凭据
  2. 使用密码保存凭据
  3. 不要保存凭据

这里的密码只是用户输入的 4 位数字。每当他想“使用密码保存凭据”时,我pushViewController都会显示默认键盘的 NumberPad 以及popviewController完成输入密码的时间。如果用户“不保存凭据”以及稍后在播放应用程序时想要使用其他身份验证选项,那么我将 TabBarController 的最后一个选项卡添加为“设置”选项卡,在其中我允许用户选择其中一个身份验证选项,弹出UIAlertView如下登录后应用程序的开始。

不要忘记在钥匙串中保存凭据

简而言之,

  1. AuthenticationViewController-> 检查登录凭据是否存储在钥匙串中

1.1。如果未存储(即 3. 不要保存凭据)-> 则显示登录页面。

1.2. 如果凭据保存在钥匙串中-> 提取它们并查看它是否与密码绑定。

1.2.1。如果它与密码绑定(即 2. 使用密码保存凭据)-> 然后显示密码页面。

1.2.2。如果它没有绑定(1.保存没有密码的凭证)->然后显示/加载您的项目TabBarController层次结构或其他内容。这里实际上是您的应用程序开始。

于 2012-05-31T04:06:40.313 回答
-1

已经加载了主故事板,只需找到它的引用,以便我可以实例化另一个根视图控制器:

UIStoryboard *mainStoryboard = self.window.rootViewController.storyboard;

self.window.rootViewController = [mainStoryboard 
    instantiateViewControllerWithIdentifier:@"view-controller-id"];
于 2014-06-16T13:29:22.530 回答