self.navigationController pushViewController不将控制器添加到堆栈

4

我现在在一个名为vcA的视图控制器上,我正在执行以下操作:

[self.navigationController pushViewController:vcB animated:YES];

并且它起作用了。vcB被推出。在vcB的viewDidAppear中,我这样做:
NSArray *controllers = self.navigationController.viewControllers;

控制器只包含一个对象,vcA!(什么?)

为什么vcB被添加到控制器数组中?有什么可以阻止这种情况发生吗?

谢谢。


你怎么知道controllers仅包含vcA? 你打印输出(NSLog)了吗? 仅通过调试器观察可能会误导。 - Eli Ganem
是的,我用NSLog记录了它。被推送的控件不在列表上,只有推动它的那个控件... - Duck
2个回答

8

我为了解决这个涉及推送视图控制器到导航控制器堆栈的问题破了一周的头。

问题是这样的:我正在使用基于导航控制的应用程序并且我有3个视图控制器,vA、vB和vC。

我正在使用以下方法从vA推送vB:

[self.navigationController pushViewController:vB animated:YES];

它起作用,但是当我试图从vB中推送vC时,vB的self.navigationController属性为nil,而且vB不在导航控制器堆栈上。什么?是的,我将vB推入了导航堆栈,并没有将其添加到其中,但即便如此,vB仍然正确显示。

我发现,在vB的viewDidLoad内部,self.navigationController不为nil,并且vB在导航控制器堆栈上,但是一旦vB的viewDidLoad结束,vB就会从导航控制器堆栈中移除,并且它的navigationController属性被设置为nil。此时,vB成为了一种幽灵控件,超出了导航控制器堆栈之外。

我不需要提到,从vB中,我无法返回vA或推送vC。

为什么会发生这种情况?

很简单,我是从一个块内部推送vB的,就像这样:

void (^ block1)() = ^(){

   [self.navigationController pushViewController:vB animated:YES];

};

因为一个UIKit函数(推送功能)被执行在一个可能不是主线程的块中,所以发生了什么。
解决方法是将推送包装在分发到主线程的块中,使用以下代码:
void (^ block1)() = ^(){
dispatch_async(dispatch_get_main_queue(),
               ^{
                   [self.navigationController pushViewController:vB animated:YES];
               });

};  

该应用程序还有一个小问题,即错误的插座连接到了viewController,但这是主要问题。这种问题很难发现,因为它很微妙。当我向导航栏添加另一个按钮时,我才发现问题:该按钮没有显示。因此,我怀疑涉及UIKit的某些事情正在发生,或在那种情况下没有发生。这里的大问题是这份代码没有崩溃、没有错误消息,仅仅表现不佳,但是正常运行。


2

我认为这与你的检查时间有关。在pushViewController方法期间,下一个视图控制器的viewWillAppear:方法(以及其他方法,如您正在检查的方法)正在被调用。我认为在所有这些方法被调用之后,在动画完成后,视图控制器才被认为是在导航堆栈上。


好的,我已经修改了方法,使其在我点击按钮时运行。现在控制器已经完全加载,问题仍然存在。推送的控制器确实没有被添加到导航栈中。 - Duck
这确实是我的问题,我完全通过编程创建了一个视图控制器,这导致在pushViewController之前调用了viewDidLoad。 - Code Baller

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接