“不支持多次推送相同的视图控制器实例”异常

问题描述 投票:0回答:15

我正在使用以下代码来检索一些消息并将它们放入我的收件箱中。

MyInboxVC *inboxVC=[MyInboxVC get ];
//upload all the pending messages
UINavigationController *devNavController=[[MyappMgr get]getDeveloperNavigationController ];

[devNavController pushViewController:inboxVC animated:YES];
[devNavController setNavigationBarHidden:NO];

我得到了例外

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Pushing the same view controller instance more than once is not supported (<MyInboxVC: 0x1452a0>)'

这是什么意思?我做错了什么?

iphone ios uiviewcontroller
15个回答
75
投票

我相信当你非常快地执行某些操作时,这种情况也会发生。我构建了这样的东西:

if(![self.navigationController.topViewController isKindOfClass:[YOURCLASS class]]) {

18
投票

首先处理崩溃,这样它就不会杀死你的应用程序:

@try {
    [self.navController pushViewController:viewController animated:NO];
} @catch (NSException * e) {
    NSLog(@"Exception: %@", e);
} @finally {
    //NSLog(@"finally");
}

如果出现错误,请使用 popTo

- (void)pushViewController:(UIViewController *)viewController {
  if (viewController) {
    @try {
        [self.navController pushViewController:viewController animated:NO];
    } @catch (NSException * ex) {
        //“Pushing the same view controller instance more than once is not supported” 
        //NSInvalidArgumentException
        NSLog(@"Exception: [%@]:%@",[ex  class], ex );
        NSLog(@"ex.name:'%@'", ex.name);
        NSLog(@"ex.reason:'%@'", ex.reason);
        //Full error includes class pointer address so only care if it starts with this error
        NSRange range = [ex.reason rangeOfString:@"Pushing the same view controller instance more than once is not supported"];

        if ([ex.name isEqualToString:@"NSInvalidArgumentException"] &&
           range.location != NSNotFound) {
            //view controller already exists in the stack - just pop back to it
            [self.navController popToViewController:viewController animated:NO];
        } else {
            NSLog(@"ERROR:UNHANDLED EXCEPTION TYPE:%@", ex);
        }
    } @finally {
        //NSLog(@"finally");
    }
  } else {
    NSLog(@"ERROR:pushViewController: viewController is nil");
  }
}

8
投票

表示从

ViewController
返回的
[MyInboxVC get]
已经在
devNavController
的导航栈中了。您不能多次将同一个对象添加到堆栈中。

显然,您之前已经推送了

MyInboxVC
。确保不再需要时将其弹出。

这就是“这是什么意思”的答案,但没有足够的信息来知道您需要做什么来解决它。

我的猜测是您的导航堆栈变得比您预期的要大,这意味着您没有像您应该的那样经常弹出。


6
投票

您是否将此作为 segue 的一部分执行?如果是,则无需将 VC 推送到导航控制器上,因为 segue 已经执行此操作了。这就是你的错误发生的原因 - 你正在推送一个已经在 NavController 堆栈上的 VC。


5
投票

这意味着当相同的视图控制器对象已经存在时,您将再次将其推送到堆栈。

[self.navigationController pushViewController:viewControllerObj animated:NO];

[self.navigationController pushViewController:viewControllerObj animated:NO];

检查您是否推入了循环,或者您是否不小心多次放置了代码..


2
投票

这个问题的主要原因,显然是如果多次调用推送视图控制器的代码。发生这种情况的原因有很多,最常见的错误是从后台线程触发回调方法时,该方法在仍在推送视图控制器时可能会多次执行。 例子: 点击按钮时在后台线程上调用服务 api,这将允许您多次按下按钮,因此推送视图控制器的回调会被多次调用。 只要您不想通过多次推送来解决原始问题,@Melvin 和 @Sam 解决方案就是有效的。


1
投票

这是 UINavigationController 的预期行为,当尝试推送堆栈中已经存在的视图控制器时会抛出异常(从 iOS 2.2 开始)。


1
投票

这种情况发生在我身上,因为点击栏按钮发生得太快,并且很难重现,除非你对按钮点击感到疯狂。 下面通过禁用按钮,启动导航推送,然后在主线程上启用按钮来修复它(因为它会在推送动画发生后被调用)。

- (void)showMore
{
    self.navigationItem.leftBarButtonItem.enabled = NO;
    [self.navigationController pushViewController:moreVC animated:YES];
    [self.navigationItem.leftBarButtonItem performSelectorOnMainThread:@selector(setEnabled:) withObject:@(YES) waitUntilDone:NO];
}

1
投票

确保您没有在导航堆栈中添加视图控制器两次。 例如 - 在下面的示例中, self.mainViewC 被推送两次,因为它最初是在 navController 中实例化的,然后在最后一行再次推送到 navController 上,这会导致此问题。

  navController=[[UINavigationController alloc] initWithRootViewController:self.mainViewC];  
  self.window.rootViewController = navController;
  [self.window makeKeyAndVisible];        
  [navController pushViewController:self.mainViewC animated:NO]; 

在这种情况下,当编写 initWithRootViewController 时,mainViewC 已经被添加到堆栈中。不再需要pushViewController。


1
投票

在我的例子中,我正在推送一个视图控制器,但随后也尝试清除导航堆栈,以便在这个新的 VC 显示后没有 VC 可以弹出

self.show(viewController, sender: nil)

if clearNavigationStack {
    self.navigationController?.viewControllers = [viewcontroller]
}

你不能在推送视图控制器后直接执行此操作,你需要等到视图控制器完全显示后再尝试重置导航堆栈


0
投票

我经历过的另一个选择是 [MyInboxVC get ] 根本不返回 MyInboxVC 对象的实例。一个明显的迹象是错误显示“不支持多次推送相同的视图控制器实例(notTheInboxVC:0x9e31660)”,即。多次推送的类不是 MyInboxVC 预期的(未分配 MyInboxVC 的失败)


0
投票

我使用 IB segue 修复了相同的问题(Swift 4):

override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
    return navigationController?.topViewController is MainController ? true : false 
}

0
投票

就我而言,我正在推动视图控制器,然后尝试在此之后立即设置导航堆栈视图控制器数组。因此,它导致转换时随机崩溃(有时崩溃,有时不崩溃):

navigationController?.pushViewController(newViewController, animated: true)
navigationController?.viewControllers = [newViewController]

我需要做的是使用单行而不是这两行(https://developer.apple.com/documentation/uikit/uinavigationcontroller/1621861-setviewcontrollers):

navigationController?.setViewControllers([newViewController], animated: true)

0
投票

在显示之前检查您的控制器是否不等于

topViewController
的当前
navigationController
,在大多数情况下都有效。

但是,如果您的控制器可以在

navigationController
的堆栈上添加另一个控制器,则最好在显示您的控制器之前使用此检查:

if navigationController?.viewControllers.contains(controller) == false {
    navigationController?.show(controller, sender: self)
}

-4
投票

[devNavController PushViewController:inboxVC 动画:NO]; 将动画设置为NO

© www.soinside.com 2019 - 2024. All rights reserved.