视图控制器堆栈
Posted
技术标签:
【中文标题】视图控制器堆栈【英文标题】:ViewController Stack 【发布时间】:2013-07-19 00:10:33 【问题描述】:所以我的应用程序逻辑存在问题,根据用户的凭据,我的应用程序的主视图是否应该在登录视图被关闭后在主视图上显示一个表格视图,或者只显示主视图关闭登录视图后查看。
所以目前,我向服务器发送一个 http post 请求,在该服务器上我得到一个令牌,然后再次调用以获取用户拥有的列表项的数量,比如游戏。
如果用户只有一个游戏,我希望显示主视图,但如果用户有多个游戏,那么用户应该看到一个 tableview,按下其中一个单元格然后模态关闭 tableview 以显示主视图。
通常我有这 3 个控制器,至少这是我正在考虑的实现方式,不确定它是否正确。
所以假设控制器A是登录,控制器B是tableview,控制器C是主视图。
控制器 C 位于堆栈的底部,而控制器 A 位于顶部。但潜在地,控制器 B 可能会或可能不会根据来自控制器 A 的信息显示。当我说堆栈底部时,我的意思是如果用户尚未登录,则将显示登录视图(控制器 A)在主视图(控制器 C)上没有动画。所以从技术上讲,主视图(控制器 C)总是被加载,但数据还没有被提供给它,只有在登录视图被正确提交的凭据关闭之后。
这里有一些在 mainviewcontroller(控制器 C)中实现的方法来检查用户是否已经登录,如果他们没有登录,那么应用程序在技术上首先通过 mainviewcontroller 然后呈现登录视图。我知道这是使用应用程序开发登录模式的方法,但我不是 100%:
- (void)showLoginViewAnimated:(BOOL)animated
NSLog(@"[MainViewController] Show login view controller");
PowerOneLoginTabBar *loginVC = [[PowerOneLoginTabBar alloc] init];
[self presentViewController:loginVC animated:NO completion:nil];
- (void)logoutHandler:(NSNotification *)notification
NSLog(@"[MainViewController] Logout handler");
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"userLoggedIn"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self showLoginViewAnimated:YES];
在主视图(viewcontroller C)的viewdidLoad中:
BOOL isUserLoggedIn = [[NSUserDefaults standardUserDefaults] boolForKey:@"userLoggedIn"];
if( !isUserLoggedIn || (!setAuthenticationKey || [setAuthenticationKey isKindOfClass:[NSNull class]]))
[self showLoginViewAnimated:NO];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(logoutHandler:) name:LOGOUT_NOTIFICATION object:self.view];
这是我在登录视图控制器(控制器 A)中实现的登录处理程序:
- (void)authenticateHandler:(NSNotification *)notification
NSLog(@"[LoginViewController] Authenticate handler");
NSDictionary *userDict = [notification userInfo];
BOOL isUserAuthenticated =
//[username isEqualToString:[userDict objectForKey:@"username"]] &&
//[password isEqualToString:[userDict objectForKey:@"password"]] &&
[api_Key isEqualToString:[userDict objectForKey:@"apiKey"]] &&
([_auth isEqualToString:[userDict objectForKey:@"authKey"]]);
[[NSUserDefaults standardUserDefaults] setBool:isUserAuthenticated forKey:@"userLoggedIn"];
[[NSUserDefaults standardUserDefaults] synchronize];
if( isUserAuthenticated )
NSLog(@"Authentificated");
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
else
NSLog(@"Not Authentificated");
[self showAlert];
并且在loginview(viewcontroller A)的viewDidLoad方法中:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(authenticateHandler:) name:AUTHENTICATE_NOTIFICATION object:self];
如果你们能给我一种模式或万无一失的理论来说明如何做到这一点,那就太好了。
因为目前,我当前关闭了显示主视图的登录视图,但随后我以模态方式(动画)呈现了 tableview,这是不可取的。所以你可以想象一个视图通过动画被关闭,然后你看到主视图,然后表格视图通过动画呈现在主视图上。除非用户只有一个游戏,否则我不希望用户在登录之前以及在他选择游戏以查看详细信息之后才能看到主视图!
请记住,tableview 显示在视图 A 和 C 之间的唯一原因是因为用户可能有超过 1 个游戏,但如果他们只有 1 个游戏,则从控制器 A 转到控制器 C,而不是控制器 A到控制器 B 到控制器 C。
【问题讨论】:
【参考方案1】:我不确定我是否完全理解这个问题,但这里有一些我希望有用的建议:
UINavigationController 特别适合一堆 vcs,尤其是在我看来,在您介绍的情况下。
主 vc 可以检查用户的登录状态并显示或不显示登录 vc。可以先假设用户有多个游戏可供选择,然后构建 vc 堆栈,如下所示:
- (void)viewDidAppear:(BOOL)animated
// notice I moved the logical or to make the BOOL more meaningful
BOOL isUserLoggedIn = [[NSUserDefaults standardUserDefaults] boolForKey:@"userLoggedIn"] || (!setAuthenticationKey || [setAuthenticationKey isKindOfClass:[NSNull class]]);
if (!isUserLoggedIn)
SelectGameVC *selectGameVC = // not sure how you build this, either alloc-init or get from storyboard
// notice animation==NO, we're putting this on the stack but not presenting it
[self.navigationController pushViewController:selectGameVC animated:NO];
LoginVC *loginVC = // alloc or use UIStoryboard instantiateViewControllerWithIdentifier
// we push this one with animation, user will see it first
[self.navigationController pushViewController:loginVC animated:YES];
loginVC 完成登录后,会问一个问题,用户有多个游戏吗?如果不止一个,则只弹出一个 vc 以显示我们堆叠在下面的 SelectGame vc,否则一直弹出。
// LoginVC.m
// login successful
if (loggedInUser.games.count > 1)
// it's underneath us, remember? we pushed it before we got here
[self.navigationController popViewControllerAnimated:YES];
else
// it's underneath us, but we don't need it, pop all the way back
[self.navigationController popToRootViewControllerAnimated:YES];
顺便说一句,你的 NSLog 让我想起我的老朋友,他曾经说“已验证”而不是“已验证”。
【讨论】:
这似乎是一种很好的实现方式。明天我会处理代码并给你一个更新。哈哈,是的,我有时会不断添加那个经过验证的词,而不是使用经过验证的精确词......我想这会让这个词感觉更复杂,我更聪明,但实际上,更无知哈哈。 :-) 我的朋友过去常说“身份验证”,这听起来像“身份识别”,它有点像,以进行真实身份识别。顺便说一句,如果你有一个 User 类,你可以在一个名为 -(BOOL)isLoggedIn; 嘿@danh,所以我想问题是我没有使用导航堆栈,我只是有多个视图控制器被模态地关闭和呈现。有什么想法吗?也许这对我来说是不可能的?因为我无法实现pop方法 我认为在没有 UINavigationController 的情况下它可能可以完成(需要一点体操),但我的建议的本质是使用 UINavigationController。真的很容易添加。如果您需要,我可以逐步为您提供(也许我也可以弄清楚如何在没有导航 vc 的情况下伪造它,但我不明白为什么这样做更好)。以上是关于视图控制器堆栈的主要内容,如果未能解决你的问题,请参考以下文章