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

重现步骤

1)创build一个导航控制器和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-( void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated方法,因为它似乎火后的viewDidAppear方法,但它没有解决问题。

我也尝试手动设置导航控制器的viewControllers认为它会跳过一些“这个视图控制器是积极的”逻辑,并允许有问题的推动工作,但事实并非如此。

唯一的解决办法是使用延迟调用来推送在secondViewController.m所需的视图控制器:

 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 250 * USEC_PER_SEC), dispatch_get_main_queue(), ^{ [self.navigationController pushViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"thirdScreen"] animated:YES]; }); 

问题

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

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

谢谢!

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

但是,这显然不是您所期望的过渡效果。 那为什么animated旗子还是有一点差距呢?

如果在-viewDidAppear:设置了一个断点,并且在animated == YESanimated == NO的情况下查看堆栈跟踪,则在视图期间调用animated == NO-viewDidAppear:时, UINavigationController布局操作。 我的钱就是这个原因,你最终的观点看起来不正确; 现在执行一个推动会在前面的推动完成之前这样做。

这就是运行循环考虑的地方。我们希望UINavigationController的视图布局(在主要运行循环的当前循环周期中发生)在完成下一个推动之前完成。 实现这个目的的一个简单方法就是将推送排队在主运行循环的下一个周期。 延迟肯定会诀窍(我相信延迟0足以延迟到下一个运行循环,所以你可以尝试用0代替250 * USEC_PER_SEC )。 另一种方法是将动作分配到主队列中:

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

所以我的回答是有点投机的,但基于一些证据。 在执行UINavigationController转换时,感觉有些不满意, -viewDidAppear:只在animation的时候表示转换的真正结束,但是看起来确实如此。

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

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