1) 创建一个导航控制器和 3 个视图控制器.
1) Create a navigation controller and 3 view controllers.
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
(又名 storyboard 中的 firstScreen)成为导航控制器的根视图控制器.
2) make firstViewController
(aka firstScreen in storyboard) the root view controller of the navigation controller.
3) 运行应用程序并注意到导航栏已更新为显示第三个屏幕的标题,但仍显示第二个屏幕的内容.
3) Run app and notice that the navigation bar has updated to show the third screen's title, but still shows the second screen's content.
我尝试过使用 UINavigationControllerDelegate
的 -( void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
方法因为它似乎在 viewDidAppear
方法之后触发,但它没有解决问题.
I've tried using UINavigationControllerDelegate
's -( void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
method since it seems to fire after the viewDidAppear
method, but it didn't fix the issue.
我还尝试手动设置导航控制器的 viewControllers
认为它会跳过一些此视图控制器处于活动状态"的逻辑并允许有问题的推送工作,但它没有.
I also tried manually setting the navigation controller's viewControllers
thinking it would skip some "this view controller is active" logic and allow the problematic push to work, but it didn't.
我能想到的唯一解决方案是使用延迟调用在 secondViewController.m 中推送所需的视图控制器:
The only solution I could come up with was using a delayed call to push the desired view controller in 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];
});
我想了解为什么这不能按预期工作.根据我在半相关问题上看到的其他一些 SO 答案,它可能与运行循环有关,但我无法确认或否认(似乎可能,因为调度推送允许它工作).
I'd like to understand why this is not working as expected. Based on some other SO answers I've seen on semi-relevant questions, it may have something to do with a run loop, but I can't confirm or deny that (seems possible since dispatching the push allows it to work).
其他有更多知识/经验的人可以启发我吗?
Can anyone else with more knowledge/experience enlighten me?
谢谢!
这是一个有趣的问题.我很有信心,如果你在 firstViewController.m 中推送第二个视图控制器时设置 animated:YES
,final UI 状态看起来与预期一样,第三个屏幕的内容和标题都正确可见.
This is an interesting question. I'm pretty confident that if you were to set animated:YES
when pushing the second view controller in firstViewController.m, the final UI state would look as expected, with the third screen's content and title both correctly visible.
但是,这显然不是您想要的过渡效果.以及为什么 animated
标志无论如何都会产生重大影响?
However, this is clearly not the transition effect you're aiming for. And why does the animated
flag make an iota of difference anyway?
如果您在 -viewDidAppear:
中设置断点并查看堆栈跟踪以了解 animated == YES
和 animated == NO 的情况
,在我看来,当 animated == NO
, -viewDidAppear:
在 UINavigationController
中的视图布局操作期间被调用.我的钱是因为你的最终观点看起来不正确;现在执行推送将在上一次推送完全完成之前执行.
If you set a break point in -viewDidAppear:
and look at the stack traces both for the case where animated == YES
and animated == NO
, it looks to me like when animated == NO
, -viewDidAppear:
is invoked during a view layout operation in the UINavigationController
. My money's on this being the reason that you're final view looks incorrect; performing a push now would be doing so before the previous push has completely finished.
这是运行循环考虑的地方.我们希望 UINavigationController
的视图布局(发生在主运行循环的当前循环循环中)在请求下一次推送之前完成.实现这一点的一个简单方法是在主运行循环的 next 循环中将推送排队.延迟肯定会解决问题(我相信 0
的延迟足以延迟到下一个运行循环周期,因此您可以尝试将 250 * USEC_PER_SEC
替换为 0
).另一种方法是将操作分派到主队列:
This is where run loop considerations come in. We want the UINavigationController
's view layout (which is happening on the main run loop's current loop cycle) to finish before asking for the next push. A simple way to achieve that is to queue the push to happen on the next cycle of the main run loop. A delay will certainly do the trick (I believe a delay of 0
is enough to delay to the next run loop cycle, so you could try replacing 250 * USEC_PER_SEC
with 0
). Another way would be to dispatch the action onto the main queue:
dispatch_async(dispatch_get_main_queue(), ^{
[self.navigationController pushViewController:[self.storyboard instantiateViewControllerWithIdentifier:@"thirdScreen"] animated:YES];
});
所以我的回答有点推测,但基于一些证据.在执行 UINavigationController
过渡时,-viewDidAppear:
仅在动画时表示过渡的真正结束,但似乎确实如此.
So my answer is kind of speculative, but based on some evidence. It feels slightly unsatisfactory that, when performing UINavigationController
transitions, -viewDidAppear:
only indicates the true end of the transition when it's animated, however that does seem to be the case.
这篇关于在 viewDidAppear 中推送视图控制器不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!