2016-04-25 2 views
0

J'ai un bug (que je rencontre déjà une deuxième fois) dans notre projet où j'ajoute simplement une vue en haut de la vue de UIViewController. Rien d'exceptionnel, quelque chose comme ceci:Problèmes d'interface utilisateur malgré le fait que les opérations UI s'exécutent sur le thread principal

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 
    self.displayEmailNotificationsIfNeeded() 
} 

Le bug est que, pour une raison quelconque mise en page automatique ne fonctionne pas correctement et ne l'ajoute pas au sommet, mais autour 60pt inférieur à celui nécessaire. Je soupçonne que ~ 60pt provient de l'ajustement manuel de la contrainte supérieure pour inclure la barre de navigation et la barre d'état, mais ce n'est pas vraiment important.

Le fait est que le problème disparaît si je lance la méthode explicitement sur la file d'attente principale, comme ceci:

override func viewDidAppear(animated: Bool) { 
    super.viewDidAppear(animated) 
    print("is main thread: ", NSThread.isMainThread()) 
    dispatch_async(dispatch_get_main_queue(), {() -> Void in 
     print("is main thread inside block: ", NSThread.isMainThread()) 
     self.displayEmailNotificationsIfNeeded() 
    }) 
} 

déclarations d'impression retour true pour les deux cas. Ce n'est pas vraiment horrible, mais juste par curiosité, je veux comprendre ce qui cause cela. Existe-t-il un moyen de déboguer cette situation et de comprendre pourquoi l'exécution explicite d'opérations sur le thread principal corrige certains problèmes d'interface utilisateur?

Répondre

1

Une supposition éclairée - ce n'est pas que le displayEmailNotificationsIfNeeded ne fonctionne pas sur le thread principal de toute façon sans l'ajouter explicitement à la file d'attente, c'est plus une question de timing. Il se peut que des éléments se déplacent à la suite d'autres contraintes de votre storyboard qui se trouvent dans un état différent une fois l'exécution de viewDidAppear terminée. L'ajout du bloc d'exécution de manière asynchrone permet de terminer viewDidAppear (et toute autre opération s'exécutant de manière synchrone dans la file d'attente principale) avant d'exécuter votre code.

Espérons que cela aide.

0

Ce n'est pas une réponse certaine car j'ai besoin de reproduire le bug pour être certain, mais voici ce que je pense pourrait se produire.

Lorsque vous exécutez le code directement, la mise en page n'est pas entièrement prête (cela dépend de l'autre code que vous pourriez avoir) et donc une mise en page incorrecte. Lorsque vous exécutez explicitement le code dans dispatch_async, vous l'exécutez également sur le thread principal, mais à un moment ultérieur et jusqu'à ce que la mise en page soit prête et que vous obteniez un résultat correct.

Également, exécutez ce code et vous devriez être capable de comprendre.

print("1"); 
    dispatch_async(dispatch_get_main_queue(), {() -> Void in 
     print("2"); 
    }) 
    print("3"); 
0

Essayez de l'exécuter dans viewWillLayoutSubviews(). Vos contrôleurs de vue .view doivent être entièrement configurés à ce stade. Notez que cette méthode peut être appelée plusieurs fois (ex: si .view est redimensionnée).