在viewDidAppear中推送视图控制器不起作用

时间:2014-01-28 21:14:55

标签: ios uinavigationcontroller

重现步骤

1)创建导航控制器和3个视图控制器。

firstViewController.m:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"DEBUG: first screen did appear");
    [self.navigationController pushViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"secondScreen"] animated:NO];
}

secondViewController.m:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"DEBUG: second screen did appear");
    [self.navigationController pushViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"thirdScreen"] animated:YES];
}

thirdViewController.m:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"DEBUG: third screen did appear");
}

2)使firstViewController(也就是故事板中的firstScreen)导航控制器的根视图控制器。

3)运行应用并注意导航栏已更新以显示第三个屏幕的标题,但仍显示第二个屏幕的内容。

注释

我尝试使用UINavigationControllerDelegate的{​​{1}}方法,因为它似乎在-( void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated方法之后触发,但它没有解决问题。

我还尝试手动设置导航控制器的viewDidAppear,认为它会跳过一些“此视图控制器处于活动状态”逻辑并允许有问题的推送工作,但事实并非如此。

解决方案

我能想出的唯一解决方案是使用延迟调用在 secondViewController.m 中推送所需的视图控制器:

viewControllers

问题

我想了解为什么这不能按预期工作。基于我在半相关问题上看到的其他一些SO答案,它可能与运行循环有关,但我无法确认或否认(似乎可能因为调度推送允许它工作)。 / p>

能有更多知识/经验的人能够启发我吗?

谢谢!

2 个答案:

答案 0 :(得分:3)

这是一个有趣的问题。我非常有信心,如果您在 firstViewController.m 中推送第二个视图控制器时设置animated:YES,则最终 UI状态将显示为预期,第三个屏幕的内容和标题都正确可见。

但是,这显然不是您所瞄准的过渡效果。为什么animated旗帜无论如何都会产生差异呢?

如果您在-viewDidAppear:中设置了一个断点,并查看了animated == YESanimated == NO的情况下的堆栈跟踪,那么它就像animated == NO时一样,在-viewDidAppear:的视图布局操作期间调用UINavigationController。我的钱就是因为你的最终观点看起来不正确;现在执行推送将在前一次推送完成之前完成。

这就是运行循环考虑因素的来源。我们希望UINavigationController的视图布局(在主运行循环的当前循环周期中发生)在要求之前完成下一步推。实现这一目标的一种简单方法是将推送排队到主运行循环的 next 循环。延迟肯定会起作用(我相信延迟0足以延迟到下一个运行循环周期,因此您可以尝试用250 * USEC_PER_SEC替换0。另一种方法是将操作分配到主队列:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.navigationController pushViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"thirdScreen"] animated:YES];
});

所以我的答案有点推测,但基于一些证据。在执行UINavigationController转换时,-viewDidAppear:仅表示动画过渡时的真实结束,但感觉似乎确实如此。感觉有点令人不满意。

答案 1 :(得分:0)

不确定为什么这不起作用,可能与时间有关。但是,要将多个视图控制器推送到导航控制器,首选方法是使用setViewControllers:animated:

NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[navigationController viewControllers]];
[viewControllers addObjectsFromArray:viewControllersToPush];
[navigationController setViewControllers:viewControllers animated:YES];