50

I am using the following code to retrieve some messages and putting them into my inbox.

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

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

I get the exception

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

What does it mean? What am I doing wrong?

Cezar
  • 55,636
  • 19
  • 86
  • 87
Suchi
  • 9,989
  • 23
  • 68
  • 112

14 Answers14

74

I believe when you do some actions really fast this can happens too. I build something in like this:

if(![self.navigationController.topViewController isKindOfClass:[YOURCLASS class]]) {
Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
Melvin
  • 3,421
  • 2
  • 37
  • 41
18

Firstly handle the crash so it doesnt kill your app:

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

Then if you get the error use 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");
  }
}
Sam Spencer
  • 8,492
  • 12
  • 76
  • 133
brian.clear
  • 5,277
  • 2
  • 41
  • 62
8

It means that the ViewController returned from [MyInboxVC get] is already in the navigation stack of devNavController. You can not add the same object to the stack multiple times.

Apparently, you already have a MyInboxVC pushed earlier. Insure that you've popped it when it was no longer needed.

That's the "what's it mean" answer, but don't have enough info to know what you need to do to fix it.

My guess is your Navigation Stack is growing larger than you are expecting, meaning you are not popping as often as you should.

MarkPowell
  • 16,482
  • 7
  • 61
  • 77
6

Are you performing this as part of a segue? If you are, there is no need to push a VC onto your Navigation Controller because the segue will do it already. That is why your error is occurring - you are pushing a VC that is already on the stack of the NavController.

micnguyen
  • 1,419
  • 18
  • 25
5

It means you are pushing the same viewcontroller object to stack again when it's already in there.

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

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

check if u r pushing inside a loop or if u've accidentally placed the code more than one time..

Durai Amuthan.H
  • 31,670
  • 10
  • 160
  • 241
2

The Main Reason for this problem, obviously if the code that pushed the view controller is called more than once. This could occur for many reasons, most common mistake when a callback method is triggered from a background thread, where this method could be executed more than once while it is still pushing the view controller. Example: Calling a service api on background thread when tapping a button, which will allow you to press the button more than once, and therefore the callback which pushes the view controller get called more than once. @Melvin and @Sam solution is valid as long as you do not want to fix the original problem by not pushing more than once.

Elie
  • 21
  • 1
1

This was happening to me on a bar button click happening too fast, and was hard to reproduce, unless you went nuts on the button taps. The following fixed it by disabling the the button, starting the nav push, then enabling the button on the main thread (because it would be called after animation from the push occurred).

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

Make sure you are not adding the view controller twice in the navigation stack. Eg - in below example self.mainViewC is pushed twice because it is initially instantiated in the navController, and is then pushed onto the navController again in the last line, which would cause this issue.

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

In this case mainViewC has already been added to stack when initWithRootViewController was written. There is no need of pushViewController again.

Natalia
  • 1,308
  • 16
  • 23
Kavish
  • 76
  • 4
1

In my case i was pushing a viewcontroller, but then also trying to clear the navigation stack so that there was no vc's to pop to after this new VC had shown

self.show(viewController, sender: nil)

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

you cant do this directly after pushing a viewcontroller, you will need to wait till the viewcontroller has fully shown before trying to reset the navigation stack

Fonix
  • 11,447
  • 3
  • 45
  • 74
1

This is an expected behavior of UINavigationController where an exception is thrown when trying to push a view controller which is already present in the stack (Its there from iOS 2.2).

Sivaprasad
  • 56
  • 1
0

Another option that I have experienced is that [MyInboxVC get ] is not returning an instance of a MyInboxVC object at all. A tell tale sign of this would be that the error is saying 'Pushing the same view controller instance more than once is not supported (notTheInboxVC: 0x9e31660)' ie. the class being pushed more than once is not the MyInboxVC expected (a fall through from MyInboxVC not being allocated)

arcady bob
  • 1,536
  • 1
  • 10
  • 5
0

I fixed the same issue (Swift 4) with IB segue using :

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

In my case, I was pushing view controller and then trying to set array of navigation stack view controllers immediately after that. So it resulted in random crashes on transition (sometimes it crashed, sometimes it did not):

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

What I needed to do, is to use single line instead of those two (https://developer.apple.com/documentation/uikit/uinavigationcontroller/1621861-setviewcontrollers):

navigationController?.setViewControllers([newViewController], animated: true)
arnas
  • 21
  • 4
-3

[devNavController pushViewController:inboxVC animated:NO]; Set animated as NO

Deepak Sasindran
  • 494
  • 1
  • 6
  • 13