在Xcode 5.0.2中,我创建了一个iPhone应用程序(完整的应用程序code is on GitHub,请运行pod install
一次 - SDWebImage
),其中显示社交网络列表( Facebook,Google +等),然后 - 在另一个视图中 - UIWebView
显示OAuth2网页,然后是第三个包含用户头像和详细信息(名字,姓氏等)的视图:
(此处显示the fullscreen screenshot of the storyboard)
在我在上一个视图中显示用户头像和详细信息之前,我将用户数据保存到NSUserDefaults
。
我的问题是:当用户下次启动应用时,NSUserDefaults
中已存在用户数据 - 如何跳过前2个视图并显示(没有任何动画) )具有这些用户详细信息的最后一个视图?
我已将以下代码添加到AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *key = [defaults objectForKey:@"key"];
User *user = [User loadForKey:key];
if (user) {
UINavigationController *nc = (UINavigationController*)self.window.rootViewController;
// XXX how to load the last view here? XXX
}
return YES;
}
并且可以看到,用户数据正在加载好,但我不明白如何跳转到最后一个视图(特别是因为大多数UI都是在故事板中定义的)?
更新:我已尝试使用AppDelegate.m中的以下代码(并在最后一个视图中分配Details
StoryboardID)来关注Tommy Alexander的建议(谢谢!):< / p>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *key = [defaults objectForKey:@"key"];
User *user = [User loadForKey:key];
if (user) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *uvc = [storyboard instantiateViewControllerWithIdentifier:@"Details"];
NSLog(@"XXX uvc=%@ user=%@", uvc, user);
[self.window.rootViewController presentViewController:uvc animated:YES completion:nil];
}
return YES;
}
虽然最后一个视图(带有用户头像和详细信息的UserViewController)似乎可以实例化,但是我收到以下警告并且应用程序没有跳到上一个视图:
MyAuth[3917:70b] XXX uvc=<UserViewController: 0x8acbac0> user=
VK
59751265
Alexander
Farber
1945522
http://cs319319.vk.me/v319319265/b7df/TnyKeffL_mU.jpg
0
MyAuth[3917:70b] Warning: Attempt to present <UserViewController: 0x8acbac0> on <UINavigationController: 0x8bb3a30> whose view is not in the window hierarchy!
更新2 :当我将上述代码移至第一个视图的viewDidLoad
(MasterViewController.m,用户可以选择社交网络时),然后我得到另一个警告:
MyAuth[1358:70b] XXX uvc=<UserViewController: 0x8a97430> user=
FB
597287941
Alexander
Farber
Bochum, Germany
http://graph.facebook.com/597287941/picture?type=large
0
MyAuth[1358:70b] Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x8a893e0>.
更新3:感谢您的宝贵答案!我最终使用了Leonty Deriglazov的建议:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc1 = [storyboard instantiateViewControllerWithIdentifier:@"Master"];
//UIViewController *vc2 = [storyboard instantiateViewControllerWithIdentifier:@"Login"];
UIViewController *vc3 = [storyboard instantiateViewControllerWithIdentifier:@"User"];
User *user = [User load];
NSArray *controllers = (user ? @[vc1, vc3] : @[vc1]);
UINavigationController *nc = (UINavigationController *)self.window.rootViewController;
[nc setViewControllers:controllers];
return YES;
}
答案 0 :(得分:14)
简而言之,最直接的解决方案是使用-[UINavigationController setViewControllers:animated:]
。
您需要执行以下操作才能达到您想要的效果:
-[UINavigationController setViewControllers:]
。就是这样。 -[AppDelegate application:didFinishLaunchingWithOptions:]
中的代码可能如下所示(当然,在检查跳过条件后):
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc1 = [storyboard instantiateViewControllerWithIdentifier:@"MyAuth"]; //if you assigned this ID is storyboard
UIViewController *vc2 = [storyboard instantiateViewControllerWithIdentifier:@"Login"]; //if you assigned this ID is storyboard
UIViewController *vc3 = [storyboard instantiateViewControllerWithIdentifier:@"Details"];
NSArray *controllers = @[vc1, vc2, vc3];
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController setViewControllers:controllers];
如果您只将其粘贴到-[AppDelegate application:didFinishLaunchingWithOptions:]
,您会发现它立即生效。
答案 1 :(得分:4)
打破视图层次结构总会产生奇怪的行为。
通过使用下面提到的方法,用户将无法注意到LoginViewController已呈现,然后我们已推送到详细信息屏幕。
这种方法对我来说一直很有用
在LoginViewController.m文件中
- (void)viewDidLoad
{
if (user) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UserViewController *userViewController = [storyboard instantiateViewControllerWithIdentifier:@"Details"];
[self.navigationController pushViewController:listViewVC animated:YES];
}
}
在UserViewController.m文件中
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
if (user) {
self.navigationItem.hidesBackButton = YES;
}
}
答案 2 :(得分:3)
我认为您的问题始于您最初的Storyboard设置。我会使用类似下图的内容。
我会创建User View controller
我的根视图控制器,并在有或没有动画的情况下以模态方式显示登录视图控制器。
一旦登录成功,解除视图控制器将非常方便。如果用户稍后注销,您只需要再次显示登录视图控制器。
答案 3 :(得分:3)
我认为你可以这样做:
if (hasUser) {
MyFirstViewController *firstViewController = [myStoryboard instantiateViewControllerWithIdentifier:@"FirstViewControllerStoryboardId"];
SecondViewController *secondViewController = [myStoryboard instantiateViewControllerWithIdentifier:@"SecondViewControllerStoryboardId"];
[myNavigationController pushViewController:firstViewController animated:NO];
[myNavigationController pushViewController:secondViewController animated:YES];
}
这样您就不会有任何动画,并且会遵守导航堆栈。 更改“动画”布尔值以播放动画。
希望它有所帮助!
答案 4 :(得分:2)
根据您的屏幕工作流程,您有一个导航控制器,其他视图控制器被推入其中。
因此,逻辑很简单:如果用户被缓存将详细信息视图控制器设置为导航视图控制器的根,则不执行任何操作(将使用故事板的默认设置)。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *nc = (UINavigationController*)self.window.rootViewController;
if (hasUser) {
UIViewController *vc = [nc.storyboard instantiateViewControllerWithIdentifier:@"DetailsViewController"];
nc.viewControllers = @[vc];
}
return YES;
}
更新
如果您需要返回上一个视图控制器(例如从详细信息到表格),您可以在导航控制器中设置整个导航层次结构:
UINavigationController *nc = (UINavigationController*)self.window.rootViewController;
if (hasUser) {
UIViewController *vc = [nc.storyboard instantiateViewControllerWithIdentifier:@"DetailsViewController"];
[nc pushViewController:vc animated:NO];
}
答案 5 :(得分:1)
尝试在IB的Attributes Inspector中为最后一个UIViewController提供一个StoryBoardID。然后,一旦确定您是否在NSUSerDefault中有用户:
- 获取对故事板的引用:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
- 启用最后一个视图控制器的实例(记得导入上一个视图控制器.h文件):
UIViewController *myController = [storyboard instantiateViewControllerWithIdentifier:@"StoryBoardID"];
- 现在VC:
[self presentViewController:myController animated:YES completion:nil];
答案 6 :(得分:1)
使用此:
[self.presentingViewController dismissViewControllerAnimated:NO completion:^{
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}];
最好的方法是使用UnwindSegue ..
What are Unwind segues for and how do you use them?
如果评论不清晰则更新
我不知道..
也许试试这个
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *uvc = [storyboard instantiateViewControllerWithIdentifier:@"Details"];
[self.window setRootViewController:uvc];
如果没有,那么将UINavigationController设为rootViewController并将ivc作为其rootViewController ..
希望有所帮助
答案 7 :(得分:1)
我在其中一个应用中执行的操作是,我从rootViewController
到我要跳过的屏幕(在您的示例中,从MyAuth到详细信息)中有一个额外的segue。然后,当我显示UINavigationController
时,我还在rootViewController
中设置了一个变量,指定我是否要跳到另一个屏幕。最后,在视图控制器的viewDidLoad:
中,我做了一个检查:
// Check if we want to skip to another screen
if (self.skipToDetails == YES) {
[self performSegueWithIdentifier:@"detailsView" sender:nil];
}
如果在故事板文件中关闭此segue的动画,则用户根本看不到第一个屏幕。
此外,您需要在详细信息屏幕中将hidesBackButton
设置为YES
。
修改当您从"unbalanced calls to begin/end"
中的原始(rootViewController
)VC转移到另一个VC(推送或模式)时,会发生viewDidLoad:
。将代码移至viewDidAppear:
应该会有所帮助。
答案 8 :(得分:1)
@Alexander请查看截图,你可以像这样管理控制器:
在用户视图控制器中使用以下代码:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *key = [defaults objectForKey:@"key"];
User *user = [User loadForKey:key];
if (!user) {
MasterViewController *loginController = [self.storyboard instantiateViewControllerWithIdentifier:@"MasterViewController"];
[self presentViewController:masterController animated:YES completion:nil];
}
答案 9 :(得分:1)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *key = [defaults objectForKey:@"key"];
User *user = [User loadForKey:key];
UINavigationController *navcon = (UINavigationController *)self.window.rootViewController;
if (hasUser) {
UIViewController *viewcon = [navcon.storyboard instantiateViewControllerWithIdentifier:@"DetailsViewController"];
[navcon pushViewController:viewcon animated:NO]; }
}
else
{
UIViewController *viewcon = [navcon.storyboard instantiateViewControllerWithIdentifier:@"UserViewController"];
[navcon pushViewController:viewcon animated:NO];}
}