web-dev-qa-db-fra.com

L'exception "Pousser plusieurs fois la même instance de contrôleur de vue n'est pas prise en charge"

J'utilise le code suivant pour récupérer des messages et les mettre dans ma boîte de réception. 

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

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

Je reçois l'exception 

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

Qu'est-ce que ça veut dire? Qu'est-ce que je fais mal?

40
Suchi

Je crois que lorsque vous faites des actions vraiment rapides, cela peut arriver aussi. Je construis quelque chose comme ça:

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

modifier//

cela se produit plus souvent sur d'anciens appareils dotés d'animations lentes, comme l'iPhone 3 ou 3gs

68
Melvin

Tout d'abord, gérez le crash pour qu'il ne tue pas votre application:

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

Ensuite, si vous obtenez l'erreur, utilisez 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");
  }
}
19
brian.clear

Cela signifie que la ViewController renvoyée par [MyInboxVC get] est déjà dans la pile de navigation de devNavController. Vous ne pouvez pas ajouter le même objet à la pile plusieurs fois. 

Apparemment, vous avez déjà une MyInboxVC poussée plus tôt. Assurez-vous que vous l'avez sauté quand il n'était plus nécessaire. 

C'est la réponse "Qu'est-ce que cela signifie", mais vous n'avez pas assez d'informations pour savoir ce que vous devez faire pour résoudre le problème.

À mon avis, votre pile de navigation est en train de devenir plus grosse que prévu, ce qui signifie que vous ne sautez pas aussi souvent que vous le devriez.

6
MarkPowell

Est-ce que vous effectuez cela dans le cadre d'une transition? Si vous l'êtes, il n'est pas nécessaire d'insérer un VC sur votre contrôleur de navigation car la division le fera déjà. C'est pourquoi votre erreur se produit - vous poussez un VC déjà sur la pile de NavController.

5
micnguyen

Cela signifie que vous poussez le même objet viewcontroller pour le réempiler quand il y est déjà.

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

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

vérifiez si vous poussez dans une boucle ou si vous avez accidentellement placé le code plus d'une fois.

3
Durai Amuthan.H

Cela m’arrivait si un clic sur un bouton de barre se produisait trop rapidement et était difficile à reproduire, à moins que vous ne deveniez fou. Ce qui suit l'a corrigé en désactivant le bouton, en démarrant le nav Push, puis en activant le bouton sur le thread principal (car il serait appelé après l'animation du Push).

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

La raison principale de ce problème, évidemment si le code qui a poussé le contrôleur de vue est appelé plusieurs fois. Cela peut se produire pour plusieurs raisons, notamment l'erreur la plus courante lorsqu'une méthode de rappel est déclenchée à partir d'un thread en arrière-plan, cette méthode pouvant être exécutée plusieurs fois alors qu'elle pousse toujours le contrôleur de vue. Exemple: Appeler une api de service sur un thread d'arrière-plan lorsque vous appuyez sur un bouton, ce qui vous permettra d'appuyer plusieurs fois sur le bouton. Par conséquent, le rappel qui pousse le contrôleur de vue est appelé plus d'une fois. @ Melvin et la solution @Sam sont valables tant que vous ne voulez pas résoudre le problème initial en ne poussant pas plus d'une fois. 

1
Elie

Il s'agit d'un comportement attendu de UINavigationController, dans lequel une exception est levée lors de la tentative d'envoi d'un contrôleur de vue déjà présent dans la pile (à partir de iOS 2.2). 

1
Sivaprasad

Assurez-vous de ne pas ajouter le contrôleur de vue deux fois dans la pile de navigation . Exemple: dans l'exemple ci-dessous, self.mainViewC est poussé deux fois car il est initialement instancié dans navController, puis à nouveau sur navController à la dernière ligne , ce qui causerait ce problème.

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

Dans ce cas, mainViewC a déjà été ajouté à la pile lors de l'écriture de initWithRootViewController. PushViewController n'est pas nécessaire à nouveau. 

0
Kavish

J'ai corrigé le même problème (Swift 4) avec IB Segue en utilisant: 

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

Une autre option que j'ai expérimentée est que [MyInboxVC get] ne renvoie pas du tout une instance d'un objet MyInboxVC. Un signe révélateur de cela serait que l'erreur indique "Pousser plusieurs fois la même instance de contrôleur de vue n'est pas pris en charge (notTheInboxVC: 0x9e31660)" c'est-à-dire. la classe étant poussée plus d'une fois n'est pas la MyInboxVC attendue (une défaillance de MyInboxVC n'est pas allouée)

0
arcady bob