我刚刚开始学习iOS编程,到目前为止,我在这里找到的教程和答案对前进有很大帮助。然而,这个特殊的问题一直困扰着我一整晚,我找不到"感觉正确"的答案。
我正在编写一个连接到远程服务的应用程序,用户需要先登录才能使用它。当他们开始使用应用程序时,他们的第一个视图应该是登录对话框;当他们之前进行身份验证时,他们会立即看到"概述"页。
该项目使用故事板 - 我认为这是一个很棒的功能 - 因此选择和加载根视图控制器的大部分代码都已得到处理。我认为添加逻辑的最佳位置是AppDelegate
的application:didFinishLaunchingWithOptions:
方法:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
// select my root view controller here based on credentials present or not
return YES;
}
但这带来了两个问题:
在此特定委托方法中,已根据情节提要选择(并加载?)根视图控制器。我可以移动到加载过程中的较早位置以覆盖第一个视图控制器选择,还是会不必要地使事情复杂化?
要覆盖第一个视图控制器,我需要对故事板的引用,但我找不到比使用
UIStoryboard
的storyboardWithName:bundle:
构造函数更好的方法。这感觉不对,应用程序应该已经引用了故事板,但是我如何访问它?
更新
我解决了我遇到的第二个问题,因为我在这里找到了答案:
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];
您可以重置窗口的根视图控制器
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:
(NSDictionary *)launchOptions
{
if(your_condition) {
UIViewController *newRoot = [your implementation];
self.window.rootViewController = newRoot;
}
return YES;
}
这对我有用,Xcode5.0.1
我和你有类似的场景。我的应用程序使用 UINavigationController
作为根视图控制器。如果用户已登录,我想向他/她提供NotLoggedInViewController
,而如果已登录,我想显示LoggedInViewController
。
在情节提要中,UINavigationController
只能有一个子级,因此您必须能够以编程方式为其分配另一个根视图控制器。
我首先创建一个自定义导航控制器类,将其命名为 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];
}
我几乎没有使用过故事板,可能这不是你问题的确切答案。但是我会建议你一些我在不使用故事板的情况下在我的项目中所做的。
在didFinishLaunchingWithOptions
中,AuthenticationViewController 是第一个加载的视图。它询问登录凭据。输入后,它将输入项目使用的实际视图控制器(即选项卡栏和所有)。
添加到项目中的有趣功能是,当您输入凭据时,我弹出了一个UIAleretView
,要求用户选择三个选项之一。
- 保存没有密码的凭据
- 使用密码保存凭据
- 不保存凭据
这里的密码只不过是用户输入的 4 位数字。每当他想"使用密码保存凭据"时,我都会pushViewController
显示默认键盘的NumberPad instad,并在完成输入引脚时显示popviewController
。如果用户"不保存凭据",稍后在玩应用程序时想要使用其他身份验证选项,那么我将TabBarController的最后一个选项卡添加为"设置"选项卡,我允许用户在其中选择其中一个身份验证选项,在登录后应用程序启动开始时弹出UIAlertView
。
不要忘记将凭据保存在钥匙串中
简而言之
- 身份验证视图控制器-> 检查登录凭据是否存储在钥匙串中
1.1. 如果未存储(即 3.不要保存凭据)->,然后显示登录页面。
1.2. 如果凭据保存在钥匙串中>请提取它们并查看它是否与密码绑定。
1.2.1. 如果它与密码绑定(即 2.使用密码保存凭据)-> 然后显示密码页面。
1.2.2. 如果未平局 (1.保存没有密码的凭据)->然后显示/加载项目的TabBarController
层次结构或其他内容。这里实际上是您的应用程序启动。
在主情节提要已经加载的情况下,只需找到它的引用,以便我可以实例化另一个根视图控制器:
UIStoryboard *mainStoryboard = self.window.rootViewController.storyboard;
self.window.rootViewController = [mainStoryboard
instantiateViewControllerWithIdentifier:@"view-controller-id"];