Tentative de présenter UIViewController sur UIViewController dont la vue n'est pas dans la hiérarchie des fenêtres

599

Je viens de commencer à utiliser Xcode 4.5 et j'ai eu cette erreur dans la console:

Avertissement: essayez de présenter <finishViewController: 0x1e56e0a0> sur <ViewController: 0x1ec3e000> dont la vue n'est pas dans la hiérarchie des fenêtres!

La vue est toujours présentée et tout dans l'application fonctionne bien. Est-ce quelque chose de nouveau dans iOS 6?

Voici le code que j'utilise pour changer entre les vues:

UIStoryboard *storyboard = self.storyboard;
finishViewController *finished = 
[storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];

[self presentViewController:finished animated:NO completion:NULL];
Kyle Goslan
la source
3
J'ai exactement le même problème, sauf en essayant d'appeler presentViewController:animated:completionun contrôleur de navigation. Faites-vous cela dans le délégué de l'application?
tarnfeld
Non, je le fais d'un contrôleur de vue à un autre. Avez-vous trouvé des solutions?
Kyle Goslan
Même problème sur une partie du code qui fonctionnait toujours avant d'utiliser Xcode 4.5, je présente un UINavigationController, mais encore une fois, cela a toujours fonctionné auparavant.
Emanuele Fumagalli
J'ai le même problème, non résolu. Le faire depuis le délégué de l'application et le rootviewcontroller appelant "presentViewController" en étant un UITabBarController.
darksider
3
aussi, si vous appelez cette méthode avant d'appeler makeKeyAndVisible, déplacez-la ensuite
mike_haney

Réponses:

1296

D'où appelez-vous cette méthode? J'ai eu un problème où j'essayais de présenter un contrôleur de vue modale dans la viewDidLoadméthode. La solution pour moi a été de déplacer cet appel vers la viewDidAppear:méthode.

Ma présomption est que la vue du contrôleur de vue n'est pas dans la hiérarchie des vues de la fenêtre au moment où elle a été chargée (lorsque le viewDidLoadmessage est envoyé), mais elle est dans la hiérarchie des fenêtres après sa présentation (lorsque le viewDidAppear:message est envoyé) .


Mise en garde

Si vous appelez presentViewController:animated:completion:dans le, viewDidAppear:vous pouvez rencontrer un problème où le contrôleur de vue modale est toujours présenté chaque fois que la vue du contrôleur de vue apparaît (ce qui a du sens!) Et ainsi le contrôleur de vue modale présenté ne disparaîtra jamais. .

Peut-être que ce n'est pas le meilleur endroit pour présenter le contrôleur de vue modale, ou peut-être qu'un état supplémentaire doit être conservé qui permet au contrôleur de vue de présentation de décider s'il doit ou non présenter immédiatement le contrôleur de vue modale.

James Bedford
la source
6
@James, vous avez raison, la vue n'apparaît apparemment dans la hiérarchie qu'après que viewWillAppear a été résolu et une fois que viewDidAppear a été appelé. Si telle était ma question, j'accepterais cette réponse;)
Matt Mc
6
@james Merci. L'utilisation de ViewDidAppear a également résolu le problème pour moi. Logique.
Ali
44
J'aimerais pouvoir voter deux fois. Je viens d'avoir ce problème et suis venu au fil pour constater que j'avais déjà voté la dernière fois que j'ai vu cela.
Schrockwell
7
Notez que lorsque vous modifiez le VC dans le viewDidAppear, cela provoque l'exécution d'une séquence, avec Animation. Provoque un flash / affichage de l'arrière-plan.
Vincent
2
Oui, l'astuce est le viewWillAppear: (BOOL) animé comme il est correct. Une autre chose importante que vous devez appeler le super dans la méthode, comme [super viewDidAppear: animated]; sans cela, cela ne fonctionne pas.
BootMaker
66

Une autre cause potentielle:

J'ai eu ce problème lorsque je présentais accidentellement deux fois le même contrôleur de vue. (Une fois avec performSegueWithIdentifer:sender:qui a été appelé lorsque le bouton a été enfoncé, et une deuxième fois avec une séquence connectée directement au bouton).

Effectivement, deux séquences tiraient en même temps, et j'ai eu l'erreur: Attempt to present X on Y whose view is not in the window hierarchy!

Chris Nolet
la source
4
J'ai eu la même erreur, et votre réponse ici m'a aidé à comprendre ce qui se passait, c'était bien cette erreur, corrigée à cause de vous monsieur, merci, +1
samouray
1
J'ai supprimé l'ancien segue et connecté VC à VC. Existe-t-il un moyen de connecter le bouton du storyBoard au VC parce que cette façon ne fait que continuer à l'erreur pour moi?
MCB
J'ai eu la même erreur, votre réponse a résolu mon problème, merci de votre attention. Sincères amitiés.
iamburak
1
lol, accidentellement, je créais également deux vc: à partir du bouton et de performSegue, merci pour le conseil !!!
Borzh
1
Dans mon cas, j'appelais present(viewController, animated: true, completion: nil)dans une boucle.
Samo
38

viewWillLayoutSubviewset viewDidLayoutSubviews(iOS 5.0+) peuvent être utilisés à cette fin. Ils sont appelés plus tôt que viewDidAppear.

Jonny
la source
3
Pourtant, ils sont également utilisés à d'autres occasions, donc je pense qu'ils pourraient être appelés plusieurs fois dans la "durée de vie" d'une vue.
Jonny
Ce n'est pas non plus la raison d'être des méthodes - comme son nom l'indique. viewDidAppear est correct. La lecture du cycle de vie de la vue est une bonne idée.
tooluser
C'est la meilleure solution. Dans mon cas, la présentation dans viewDidAppear provoque une fraction de seconde d'affichage du contrôleur de vue avant le chargement du modal, ce qui est inacceptable.
TMilligan
Cette réponse a fonctionné le mieux pour moi lorsque j'essayais d'afficher une alerte. L'alerte ne s'afficherait pas lorsque je la mettrais dans viewDidLoad et viewWillAppear.
uplearnedu.com
26

Pour afficher une sous-vue à la vue principale, veuillez utiliser le code suivant

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController presentViewController:composeViewController animated:YES completion:nil];

Pour rejeter toute sous-vue de la vue principale, veuillez utiliser le code suivant

UIViewController *yourCurrentViewController = [UIApplication sharedApplication].keyWindow.rootViewController;

while (yourCurrentViewController.presentedViewController) 
{
   yourCurrentViewController = yourCurrentViewController.presentedViewController;
}

[yourCurrentViewController dismissViewControllerAnimated:YES completion:nil];
abdul sathar
la source
A travaillé pour moi aussi
Aziz Javed
17

J'ai également rencontré ce problème lorsque j'ai essayé de présenter un fichier UIViewControllerin viewDidLoad. La réponse de James Bedford a fonctionné, mais mon application a affiché l'arrière-plan en premier pendant 1 ou 2 secondes.

Après quelques recherches, j'ai trouvé un moyen de résoudre ce problème en utilisant le addChildViewController.

- (void)viewDidLoad
{
    ...
    [self.view addSubview: navigationViewController.view];
    [self addChildViewController: navigationViewController];
    ...
}
sunkehappy
la source
9
Je pense que vous manquez [navigationViewController didMoveToParentViewController: self]
foFox
2
J'ai essayé votre code, avec la suggestion de foFox, et quand je vais le supprimer de son parent, il ne disparaîtra pas. Lololol. Toujours coincé sans solution.
Logicsaurus Rex
Fonctionne dans Swift3.1
Kang Byul
@sunkehappy au-dessus de deux lignes à utiliser avant le presentviewcontroller, mais son planté pourquoi?
Iyyappan Ravi
14

Probablement, comme moi, vous avez une mauvaise racine viewController

Je veux afficher un ViewControllerdans un non-UIViewControllercontexte,

Je ne peux donc pas utiliser un tel code:

[self presentViewController:]

Donc, je reçois un UIViewController:

[[[[UIApplication sharedApplication] delegate] window] rootViewController]

Pour une raison quelconque (bogue logique), le rootViewControllerest autre chose que prévu (un normal UIViewController). Ensuite, je corrige le bogue, en le remplaçant rootViewControllerpar un UINavigationController, et le problème a disparu.

Sanbrother
la source
8

TL; DR Vous ne pouvez avoir qu'un seul rootViewController et son dernier présenté. N'essayez donc pas de faire en sorte qu'un viewcontroller présente un autre viewcontroller alors qu'il est déjà présenté, qui n'a pas été rejeté.

Après avoir fait mes propres tests, je suis arrivé à une conclusion.

Si vous avez un rootViewController que vous souhaitez tout présenter, vous pouvez rencontrer ce problème.

Voici mon code rootController (ouvert est mon raccourci pour présenter un viewcontroller depuis la racine).

func open(controller:UIViewController)
{
    if (Context.ROOTWINDOW.rootViewController == nil)
    {
        Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
        Context.ROOTWINDOW.makeKeyAndVisible()
    }

    ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}

Si j'appelle ouvert deux fois de suite (quel que soit le temps écoulé), cela fonctionnera très bien lors de la première ouverture, mais PAS lors de la deuxième ouverture. La deuxième tentative d'ouverture entraînera l'erreur ci-dessus.

Cependant, si je ferme la dernière vue présentée et que j'appelle open, cela fonctionne très bien lorsque j'appelle à nouveau open (sur un autre viewcontroller).

func close(controller:UIViewController)
{
    ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}

Ce que j'ai conclu, c'est que le rootViewController de seulement le MOST-RECENT-CALL est sur la hiérarchie des vues (même si vous ne l'avez pas supprimé ou supprimé une vue). J'ai essayé de jouer avec tous les appels du chargeur (viewDidLoad, viewDidAppear et faire des appels de répartition retardés) et j'ai trouvé que la seule façon de le faire fonctionner est d'appeler SEULEMENT le plus haut contrôleur de vue.

Agresseur
la source
Cela semble être un problème beaucoup plus courant que les nombreuses réponses qui ont voté contre la vôtre. Malheureusement, cela a été extrêmement utile
rayepps
oui tout va bien mais quelle est la solution ... j'ai un fil de travail d'arrière-plan allant à un serveur et affichant des storyboards à gauche et au centre et la méthodologie entière est fausse .. c'est horrible .. ce qui devrait être un jeu d'enfant est tout à fait un blague parce que je veux faire dans le fil de fond est: wait wait decide push screen to frontet c'est IMPOSSIBLE est IOS ????
M. Heelis
5

Mon problème était que j'effectuais UIApplicationDelegatela didFinishLaunchingWithOptionsméthode de transition avant d'appeler makeKeyAndVisible()à la fenêtre.

Adam Johns
la source
Comment? peux-tu élaborer? je suis confronté au même problème. ceci est mon code laissé initialViewControlleripad: UIViewController = mainStoryboardIpad.instantiateViewController (withIdentifier: "SplashController") comme UIViewController self.window .rootViewController = initialViewControlleripad self.window .makeKeyAndVisible ()?
Shahtaj khalid
4

Dans ma situation, je n'ai pas pu mettre la mienne dans une dérogation de classe. Alors, voici ce que j'ai obtenu:

let viewController = self // I had viewController passed in as a function,
                          // but otherwise you can do this


// Present the view controller
let currentViewController = UIApplication.shared.keyWindow?.rootViewController
currentViewController?.dismiss(animated: true, completion: nil)

if viewController.presentedViewController == nil {
    currentViewController?.present(alert, animated: true, completion: nil)
} else {
    viewController.present(alert, animated: true, completion: nil)
}
George_E
la source
3

J'ai eu le même problème. J'ai dû intégrer un contrôleur de navigation et présenter le contrôleur à travers. Voici l'exemple de code.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    UIImagePickerController *cameraView = [[UIImagePickerController alloc]init];
    [cameraView setSourceType:UIImagePickerControllerSourceTypeCamera];
    [cameraView setShowsCameraControls:NO];

    UIView *cameraOverlay = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 768, 1024)];
    UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"someImage"]];
    [imageView setFrame:CGRectMake(0, 0, 768, 1024)];
    [cameraOverlay addSubview:imageView];

    [cameraView setCameraOverlayView:imageView];

    [self.navigationController presentViewController:cameraView animated:NO completion:nil];
//    [self presentViewController:cameraView animated:NO completion:nil]; //this will cause view is not in the window hierarchy error

}
repos
la source
3

Si vous avez un objet AVPlayer avec une vidéo lue, vous devez d'abord mettre la vidéo en pause.

Vlad
la source
Je veux dire que la vidéo doit être arrêtée / interrompue en premier.
Vlad
en fait cela m'a aidé, cela m'a conduit ensuite à ce stackoverflow.com/questions/20746413/…
Omar N Shamali
3

J'ai eu le même problème. Le problème était que le performSegueWithIdentifier a été déclenché par une notification, dès que j'ai mis la notification sur le thread principal, le message d'avertissement avait disparu.

rouge
la source
3

Cela fonctionne bien, essayez ceci. Lien

UIViewController *top = [UIApplication sharedApplication].keyWindow.rootViewController;
[top presentViewController:secondView animated:YES completion: nil];
vijay
la source
3

Au cas où cela aiderait quelqu'un, mon problème était extrêmement stupide. Tout à fait ma faute bien sûr. Une notification déclenchait une méthode qui appelait le modal. Mais je ne supprimais pas la notification correctement, donc à un moment donné, j'aurais plus d'une notification, donc le modal serait appelé plusieurs fois. Bien sûr, après avoir appelé le modal une fois, le viewcontroller qui l'appelle n'est plus dans la hiérarchie des vues, c'est pourquoi nous voyons ce problème. Ma situation a également causé un tas d'autres problèmes, comme vous vous en doutez.

Donc, pour résumer, quoi que vous fassiez, assurez-vous que le modal n'est pas appelé plus d'une fois .

HotFudgeSunday
la source
3

Je me suis retrouvé avec un tel code qui fonctionne finalement pour moi (Swift), étant donné que vous voulez en afficher viewControllerpratiquement n'importe où. Ce code se bloquera évidemment lorsqu'il n'y a pas de rootViewController disponible, c'est la fin ouverte. Il n'inclut pas non plus le passage habituellement requis au thread d'interface utilisateur à l'aide

dispatch_sync(dispatch_get_main_queue(), {
    guard !NSBundle.mainBundle().bundlePath.hasSuffix(".appex") else {
       return; // skip operation when embedded to App Extension
    }

    if let delegate = UIApplication.sharedApplication().delegate {
        delegate.window!!.rootViewController?.presentViewController(viewController, animated: true, completion: { () -> Void in
            // optional completion code
        })
    }
}
igraczech
la source
BTW pour comprendre O do dois-je appeler cette méthode à partir de ... c'est la bibliothèque SDK sans interface utilisateur, qui affiche sa propre interface utilisateur sur votre application dans certains cas (non divulgués).
igraczech
Vous allez planter et graver si quelqu'un décide d'intégrer votre sdk dans une application dotée d'une extension. Passez un UIViewController pour abuser de votre [s] méthode (s) init sdk.
Anton Tropashko
Tu es vrai Anton. Ce code a été écrit lorsque les extensions n'existaient pas et le SDK n'est encore utilisé dans aucun d'entre eux. J'ai ajouté une clause de garde pour ignorer ce cas de bord.
igraczech
3

Ce genre d'avertissement peut signifier que vous essayez de présenter de nouvelles à View Controllertravers Navigation Controllertout ce Navigation Controllerprésente actuellement une autre View Controller. Pour le réparer Vous devez rejeter actuellement présenté View Controllerau début et à la fin présenter le nouveau. Une autre cause de l'avertissement peut être d'essayer de présenter View Controllersur un thread autre que main.

saltwat5r
la source
3

J'ai eu un problème similaire sur Swift 4.2 mais ma vue n'a pas été présentée à partir du cycle de vue. J'ai trouvé que j'avais plusieurs séquences à présenter en même temps. J'ai donc utilisé dispatchAsyncAfter.

func updateView() {

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in

// for programmatically presenting view controller 
// present(viewController, animated: true, completion: nil)

//For Story board segue. you will also have to setup prepare segue for this to work. 
 self?.performSegue(withIdentifier: "Identifier", sender: nil)
  }
}
Ashim Dahal
la source
2

Je l'ai corrigé en déplaçant la start()fonction à l'intérieur du dismissbloc de complétion:

self.tabBarController.dismiss(animated: false) {
  self.start()
}

Start contient deux appels à l' self.present()un pour un UINavigationController et à un autre pour a UIImagePickerController.

Cela m'a arrangé.

Alper
la source
1

Vous pouvez également obtenir cet avertissement lorsque vous effectuez une séquence à partir d'un contrôleur de vue incorporé dans un conteneur. La bonne solution consiste à utiliser segue depuis le parent du conteneur, et non depuis le contrôleur de vue du conteneur.

Borzh
la source
1

Vous devez écrire sous la ligne.

self.searchController.definesPresentationContext = true

au lieu de

self.definesPresentationContext = true

dans UIViewController

Coder_A_D
la source
1

Avec Swift 3 ...

Une autre cause possible à cela, qui m'est arrivée, était d'avoir une transition d'une tableViewCell à un autre ViewController sur le Storyboard. J'ai également utilisé override func prepare(for segue: UIStoryboardSegue, sender: Any?) {}lorsque la cellule a été cliquée.

J'ai résolu ce problème en effectuant une transition de ViewController à ViewController.

Devbot10
la source
1

J'ai eu ce problème et la cause principale était de s'abonner plusieurs fois à un gestionnaire de clic de bouton (TouchUpInside).

Il s'abonnait dans ViewWillAppear, qui était appelé plusieurs fois depuis que nous avions ajouté la navigation pour accéder à un autre contrôleur, puis y revenir.

Nous s
la source
1

Il m'est arrivé que la séquence dans le storyboard était une sorte de rupture . La suppression de la séquence (et la création de la même séquence exacte à nouveau) a résolu le problème.

vonox7
la source
1

Avec votre fenêtre principale, il y aura probablement toujours des moments avec des transitions incompatibles avec la présentation d'une alerte. Afin de permettre la présentation d'alertes à tout moment dans le cycle de vie de votre application, vous devez disposer d'une fenêtre distincte pour effectuer le travail.

/// independant window for alerts
@interface AlertWindow: UIWindow

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message;

@end

@implementation AlertWindow

+ (AlertWindow *)sharedInstance
{
    static AlertWindow *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[AlertWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    });
    return sharedInstance;
}

+ (void)presentAlertWithTitle:(NSString *)title message:(NSString *)message
{
    // Using a separate window to solve "Warning: Attempt to present <UIAlertController> on <UIViewController> whose view is not in the window hierarchy!"
    UIWindow *shared = AlertWindow.sharedInstance;
    shared.userInteractionEnabled = YES;
    UIViewController *root = shared.rootViewController;
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
    alert.modalInPopover = true;
    [alert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
        shared.userInteractionEnabled = NO;
        [root dismissViewControllerAnimated:YES completion:nil];
    }]];
    [root presentViewController:alert animated:YES completion:nil];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];

    self.userInteractionEnabled = NO;
    self.windowLevel = CGFLOAT_MAX;
    self.backgroundColor = UIColor.clearColor;
    self.hidden = NO;
    self.rootViewController = UIViewController.new;

    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(bringWindowToTop:)
                                               name:UIWindowDidBecomeVisibleNotification
                                             object:nil];

    return self;
}

/// Bring AlertWindow to top when another window is being shown.
- (void)bringWindowToTop:(NSNotification *)notification {
    if (![notification.object isKindOfClass:[AlertWindow class]]) {
        self.hidden = YES;
        self.hidden = NO;
    }
}

@end

Utilisation de base qui, par conception, réussira toujours:

[AlertWindow presentAlertWithTitle:@"My title" message:@"My message"];
Cœur
la source
1

Malheureusement, la solution acceptée n'a pas fonctionné pour mon cas. J'essayais de naviguer vers un nouveau contrôleur de vue juste après me détendre à partir d'un autre contrôleur de vue.

J'ai trouvé une solution en utilisant un indicateur pour indiquer quelle séquence de déroulement a été appelée.

@IBAction func unwindFromAuthenticationWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToMainTabBar = true
}

@IBAction func unwindFromForgetPasswordWithSegue(segue: UIStoryboardSegue) {
    self.shouldSegueToLogin = true
}

Ensuite, présentez le VC recherché avec present(_ viewControllerToPresent: UIViewController)

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    if self.shouldSegueToMainTabBar {
        let mainTabBarController = storyboard.instantiateViewController(withIdentifier: "mainTabBarVC") as! MainTabBarController
        self.present(mainTabBarController, animated: true)
        self.shouldSegueToMainTabBar = false
    }
    if self.shouldSegueToLogin {
        let loginController = storyboard.instantiateViewController(withIdentifier: "loginVC") as! LogInViewController
        self.present(loginController, animated: true)
        self.shouldSegueToLogin = false
    }
}

Fondamentalement, le code ci-dessus me permettra d'attraper le déroulement de la connexion / SignUp VC et d'accéder au tableau de bord, ou d'attraper l'action de déroulement du mot de passe oublié VC et d'accéder à la page de connexion.

Fan Jin
la source
1

J'ai corrigé cette erreur en stockant le plus haut viewcontroller dans une constante qui se trouve dans pendant le cycle sur rootViewController:

if var topController = UIApplication.shared.keyWindow?.rootViewController {
    while let presentedViewController = topController.presentedViewController {
        topController = presentedViewController
    }
    topController.present(controller, animated: false, completion: nil)
    // topController should now be your topmost view controller
}
Marek Baláž
la source
1

J'ai trouvé que ce bug est arrivé après la mise à jour de Xcode, je crois pour Swift 5 . Le problème se produisait lorsque j'ai lancé par programmation un enchaînement directement après avoir déroulé un contrôleur de vue.

La solution est arrivée en corrigeant un bogue connexe, à savoir que l'utilisateur était désormais en mesure de dérouler les séquences en faisant glisser la page vers le bas. Cela a brisé la logique de mon programme.

Il a été corrigé en changeant le mode de présentation sur tous les contrôleurs de vue d' Automatique à Plein écran .

Vous pouvez le faire dans le panneau d'attributs du générateur d'interface. Ou consultez cette réponse pour savoir comment procéder par programme.

Tim MB
la source
0

Je viens d'avoir ce problème aussi, mais cela n'a rien à voir avec le timing. J'utilisais un singleton pour gérer les scènes, et je l'ai défini comme le présentateur. En d'autres termes, "Self" n'était lié à rien. Je viens de faire de sa "scène" intérieure le nouveau présentateur et le tour est joué, ça a marché. (Voila perd son contact après avoir appris sa signification, heh).

Donc oui, il ne s'agit pas de "trouver par magie la bonne voie", il s'agit de comprendre où se trouve votre code et ce qu'il fait. Je suis heureux qu'Apple ait donné un message d'avertissement aussi simple en anglais, même avec émotion. Félicitations au développeur de pommes qui a fait ça !!

Stephen J
la source
0

Si d'autres solutions ne semblent pas bonnes pour une raison quelconque, vous pouvez toujours utiliser cette bonne vieille workaroundprésentation avec le retard de 0, comme ceci:

dispatch_after(0, dispatch_get_main_queue(), ^{
    finishViewController *finished = [self.storyboard instantiateViewControllerWithIdentifier:@"finishViewController"];
    [self presentViewController:finished animated:NO completion:NULL];    
});

Bien que je n'aie vu aucune garantie documentée que votre VC serait dans la hiérarchie des vues sur le moment où le bloc de répartition est planifié pour l'exécution, j'ai observé que cela fonctionnerait très bien.

L'utilisation d'un retard de 0,2 sec, par exemple, est également une option. Et la meilleure chose - de cette façon, vous n'avez pas besoin de jouer avec la variable booléenne dansviewDidAppear:

Dannie P
la source
2
Bien que cela puisse fonctionner maintenant, il n'y a aucune garantie qu'Apple changera de comportement et vous interrompra à l'avenir. Ensuite, lorsque vous reviendrez sur votre code pour essayer de corriger les choses à nouveau, vous vous demanderez pourquoi vous faisiez cette répartition apparemment inutile.
Cruinh
L'envoi avec 0 fois m'a déjà fait économiser un certain nombre de fois - parfois des choses qui devraient logiquement fonctionner ne fonctionnent normalement pas sans. Faites donc des commentaires pour vous-même et pour les autres sur les raisons pour lesquelles vous faites des choses non évidentes (pas seulement une telle dépêche) et tout devrait bien se passer.
Dannie P
2
Vous piratez simplement le problème et ne le résolvez pas.
Michael Peterson
0

Cela fonctionne pour présenter n'importe quel contrôleur de vue, si vous avez un contrôleur de navigation disponible. self.navigationController? .present (MyViewController, animé: vrai, achèvement: nul) De plus, je peux également présenter des alertes et un contrôleur de messagerie.

Gurpreet Singh
la source