web-dev-qa-db-fra.com

Appels non équilibrés pour les transitions d'apparence début/fin pour <UITabBarController: 0x197870>

J'ai lu SO à propos d'un autre utilisateur rencontrant un erreur similaire, mais cette erreur est dans un cas différent.

J'ai reçu ce message lorsque j'ai initialement ajouté un contrôleur de vue:

Unbalanced calls to begin/end appearance transitions for 
<UITabBarController: 0x197870>

La structure de l'application est la suivante:

J'ai un TabBarController à 5 onglets lié à 5 contrôleurs de vue. Dans l'onglet d'affichage initial, j'appelle un nouveau contrôleur de vue à superposer en tant qu'introduction de l'application.

J'utilise ce code pour appeler le contrôleur de vue d'introduction:

IntroVC *vc = [[IntroVC alloc] init];
[self presentModalViewController:vc animated:YES];
[vc release]; 

Une fois que ce contrôleur de vue IntroVC est apparu, l'erreur ci-dessus apparaît. 

p.s. J'utilise xCode 4.2 et iOS 5.0 SDK, et développe l'application iOS 4.3.

105
Raptor

Sans voir plus du code environnant, je ne peux pas donner de réponse définitive, mais j'ai deux théories.

  1. Vous n'utilisez pas UIViewController 's initializer désigné initWithNibName:bundle: . Essayez de l’utiliser au lieu de simplement init.

  2. De même, self peut être l'un des contrôleurs de vue du contrôleur de la barre d'onglets. Présentez toujours les contrôleurs de vue à partir du contrôleur de vue le plus élevé, ce qui signifie dans ce cas, demandez au contrôleur de barre de tabulation de présenter le contrôleur de vue de superposition au nom du contrôleur de vue. Vous pouvez toujours conserver les délégués de rappel sur le contrôleur de vue réelle, mais le contrôleur de barre d'onglets doit être présent et ignoré.

92
Jesper

J'ai corrigé cette erreur en changeant d'animation de OUI à NON.

De:

[tabBarController presentModalViewController:viewController animated:YES];

À:

[tabBarController presentModalViewController:viewController animated:NO];
38
PokerIncome.com

Tel que publié par danh

Vous pouvez générer cet avertissement en présentant le modal vc avant l'initialisation de l'application. c.-à-d. démarrer un modèle d'application d'application à onglets et présenter un vc modal au-dessus de self.tabBarController en tant que dernière ligne de l'application: didFinishLaunching. Avertissement apparaît. Solution: laisser la pile se dérouler d'abord, présenter le vc modal dans une autre méthode, appelée avec un performSelector withDelay: 0.0

Essayez de déplacer la méthode dans viewWillAppear et gardez-la afin qu'elle ne soit exécutée qu'une seule fois (il est recommandé de configurer une propriété).

15
Peter Lapisu

J'ai eu le même problème quand j'ai besoin de présenter mon login View Controller à partir d'un autre View Controller Si l'utilisateur n'est pas autorisé, je l'ai fait dans la méthode ViewDidLoad de mon Another View Controller (si non autorisé -> presentModalViewController). Quand je commence à le faire dans la méthode ViewDidAppear, j'ai résolu ce problème. Je pense que ViewDidLoad n’initialise que les propriétés, puis l’algorithme de la vue réelle commence! C'est pourquoi vous devez utiliser la méthode viewDidAppear pour effectuer des transitions modales!

3
Tolusha

J'ai eu le même problème. J'ai appelé une méthode dans viewDidLoad dans ma première UIViewController

- (void)viewDidLoad{
    [super viewDidLoad];

    [self performSelector:@selector(loadingView)
               withObject:nil afterDelay:0.5];
}

- (void)loadingView{

    [self performSegueWithIdentifier:@"loadedData" sender:self];
}

Dans la seconde UIViewController, j'ai fait de même avec un délai de 0,5 seconde. Après avoir changé le délai à une valeur supérieure, cela a bien fonctionné. C'est comme si la division ne pouvait pas être exécutée trop rapidement après une autre division.

3
Alex Cio

J'ai eu ce problème à cause d'une faute de frappe:

override func viewDidAppear(animated: Bool) {
    super.viewWillAppear(animated)

au lieu de 

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

Il appelait "WillAppear" dans le super au lieu de "DidAppear"

2
Adriano Spadoni

Une autre solution, dans de nombreux cas, consiste à s'assurer que la transition entre UIViewControllers a lieu après la procédure non appropriée (comme lors de l'initialisation) se termine, en effectuant:

__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf presentViewController:vc animated:YES];
});

Ceci est général pour aussi pushViewController:animated:, etc.

2
mllm

Je l'ai résolu en écrivant

[self.navigationController presentViewController:viewController 
                                        animated:TRUE 
                                      completion:NULL];
2
pankesh

J'ai eu beaucoup de problème avec le même problème. J'ai résolu celui-ci par

  1. Lancer ViewController à l'aide de la méthode storyboad instantiateViewControllerWithIdentifier. i.e Intro *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"introVC"];
  2. [self.tabBarController presentModalViewController : vc animated:YES];

J'ai le contrôleur de vue dans mon scénario, pour une raison quelconque, utiliser uniquement [[introvc alloc] init]; ne fonctionnait pas pour moi. 

2
Mogambolal

J'ai eu ce problème avec un code tiers. Quelqu'un a oublié de définir le super intérieur de viewWillAppear et viewWillDisappear dans une classe personnalisée TabBarController.

- (void) viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];
    // code...
}

or

- (void) viewWillDisappear:(BOOL)animated {

    [super viewWillDisappear:animated];
    // code...
}
1
J. Lopes

J'avais le même problème et je pensais poster si quelqu'un d'autre rencontrait quelque chose de similaire.

Dans mon cas, j'avais attaché un identificateur de mouvements de presse long à mon UITableViewController.

UILongPressGestureRecognizer *longPressGesture = [[[UILongPressGestureRecognizer alloc]
                                                   initWithTarget:self
                                                   action:@selector(onLongPress:)]
                                                  autorelease];
[longPressGesture setMinimumPressDuration:1];
[self.tableView addGestureRecognizer:longPressGesture];

Dans mon sélecteur onLongPress, j'ai lancé mon prochain contrôleur de vue.

- (IBAction)onLongPress:(id)sender {

    SomeViewController* page = [[SomeViewController alloc] initWithNibName:@"SomeViewController" bundle:nil];

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

    [page release];

}

Dans mon cas, j'ai reçu le message d'erreur parce que le système de reconnaissance de presse longue a été déclenché plus d'une fois et, par conséquent, mon "SomeViewController" a été poussé plusieurs fois sur la pile. 

La solution consistait à ajouter un booléen pour indiquer quand le SomeViewController avait été placé sur la pile. Lorsque ma méthode viewWillAppear de UITableViewController a été appelée, je redéfinis le booléen sur NO.

1
Dale Moore

J'ai eu la même erreur. J'ai une barre d'onglets avec 3 éléments et j'essayais inconsciemment d'appeler le contrôleur de vue racine de l'élément 1 dans l'élément 2 de ma barre d'onglets en utilisant performSegueWithIdentifier.

En réalité, il appelle le contrôleur de vue et revient au contrôleur de vue racine de l'élément 2 après quelques secondes et enregistre cette erreur.

Apparemment, vous ne pouvez pas appeler le contrôleur de vue racine d'un élément vers un autre. 

Donc au lieu de performSegueWithIdentifier 

J'ai utilisé [self.parentViewController.tabBarController setSelectedIndex:0];

J'espère que ça aide quelqu'un.

1
Gellie Ann

Dans Swift 2+ pour moi, cela fonctionne:

J'ai UITabBarViewController dans le storyboard et j'avais sélectionné propertyIndex comme ceci:

 enter image description here

Mais je le supprime et j'ajoute à ma méthode viewDidLoad de ma classe initiale, comme ceci:

override func viewDidLoad() {
   super.viewDidLoad()
   self.tabBarController?.selectedIndex = 2
}

J'espère pouvoir aider quelqu'un.

1
Dasoga

Si vous utilisez transitioningDelegate (pas le cas dans l'exemple de cette question), définissez égalementmodalPresentationStylesur.Custom.

Rapide

let vc = storyboard.instantiateViewControllerWithIdentifier("...")
vc.transitioningDelegate = self
vc.modalPresentationStyle = .Custom
1
Kof

vous devez vous assurer que - (void) beginAppearanceTransition: (BOOL) est animée: (BOOL) animée et - (void) endAppearanceTransition est créée ensemble dans la classe.

0
zszen

En fait, vous devez attendre la fin de l'animation Push. Ainsi, vous pouvez déléguer UINavigationController et éviter de pousser jusqu'à la fin de l'animation.

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    waitNavigation = NO;
}


-(void)showGScreen:(id)gvc{

    if (!waitNavigation) {
        waitNavigation = YES;
        [_nav popToRootViewControllerAnimated:NO];
        [_nav pushViewController:gvc animated:YES];
    }
}
0
ymutlu

J'ai eu le même problème. En développant je voulais contourner les écrans. Je naviguais d'un contrôleur de vue à un autre dans viewDidLoad en appelant une méthode de sélection.

Le problème est que nous devrions laisser ViewController terminer la transition avant de passer à un autre ViewController.

Cela a résolu mon problème: le délai est nécessaire pour permettre à ViewControllers de terminer la transition avant de passer à un autre.

self.perform(#selector(YOUR SELECTOR METHOD), with: self, afterDelay: 0.5)

0
codeedoc

J'ai constaté que, si vous utilisez un storyboard, vous voudrez mettre le code qui présente le nouveau contrôleur de vue dans viewDidAppear. Il supprimera également l'avertissement "Il est déconseillé de présenter des contrôleurs de vue sur des contrôleurs de vue détachés".

0
Dan Levy

Comme @danh l'a suggéré, mon problème était que je présentais le modal vc avant que le UITabBarController soit prêt. Cependant, je me suis senti mal à l'aise de compter sur un délai fixe avant de présenter le contrôleur de vue (lors de mes tests, je devais utiliser un délai de 0.05 à 0.1s dans performSelector:withDelay:). Ma solution consiste à ajouter un bloc appelé par la méthode viewDidAppear: de UITabBarController:

PRTabBarController.h:

@interface PRTabBarController : UITabBarController

@property (nonatomic, copy) void (^viewDidAppearBlock)(BOOL animated);

@end

PRTabBarController.m:

#import "PRTabBarController.h"

@implementation PRTabBarController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (self.viewDidAppearBlock) {
        self.viewDidAppearBlock(animated);
    }
}

@end

Maintenant dans application:didFinishLaunchingWithOptions:

PRTabBarController *tabBarController = [[PRTabBarController alloc] init];

// UIWindow initialization, etc.

__weak typeof(tabBarController) weakTabBarController = tabBarController;
tabBarController.viewDidAppearBlock = ^(BOOL animated) {
    MyViewController *viewController = [MyViewController new];
    viewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
    [weakTabBarController.tabBarController presentViewController:navigationController animated:NO completion:nil];
    weakTabBarController.viewDidAppearBlock = nil;
};
0
johnboiles