J'ai souvent rencontré cette erreur dans mon OS X en utilisant swift:
"Cette application modifie le moteur de mise en page automatique à partir d'un thread d'arrière-plan, ce qui peut entraîner une corruption du moteur et des plantages étranges. Cela entraînera une exception dans une prochaine version."
J'ai ma fenêtre NSWindow et j'échange les vues vers contentView
la fenêtre. J'obtiens l' erreur lorsque j'essaie de faire un NSApp.beginSheet
sur la fenêtre ou lorsque j'ajoute un subview
à la fenêtre. J'ai essayé de désactiver le redimensionnement automatique, et je n'ai rien en utilisant la mise en page automatique. Des pensées?
Parfois ça va et rien ne se passe, d'autres fois ça me casse totalement UI
et rien ne se charge
Réponses:
Il doit être placé dans un thread différent qui permet à l'interface utilisateur de se mettre à jour dès que l'exécution de la fonction de thread est terminée:
Swift moderne:
Versions plus anciennes de Swift, avant Swift 3.
Objectif c:
la source
Vous obtenez un message d'erreur similaire lors du débogage avec des instructions d'impression sans utiliser «dispatch_async». Ainsi, lorsque vous obtenez ce message d'erreur, il est temps d'utiliser
Swift 4
Swift 3
Versions Swift antérieures
la source
dispatch_async(dispatch_get_main_queue(), ^{ /* UI related code */ });
Edit: J'ai mis à jour sa réponse, le formatage de la syntaxe fonctionne mieux là-bas.L'erreur "cette application modifie le moteur de mise en page automatique à partir d'un thread d'arrière-plan" est enregistrée dans la console longtemps après le problème réel, donc le débogage peut être difficile sans utiliser de point d'arrêt.
J'ai utilisé la réponse de @ markussvensson pour détecter mon problème et je l'ai trouvé en utilisant ce point d' arrêt symbolique (Débogage> Points d'arrêt> Créer un point d'arrêt symbolique):
[UIView layoutIfNeeded]
ou[UIView updateConstraintsIfNeeded]
!(BOOL)[NSThread isMainThread]
Générez et exécutez l'application sur l'émulateur et reproduisez les étapes qui mènent au message d'erreur (l'application sera plus lente que d'habitude!). Xcode arrêtera alors l'application et marquera la ligne de code (par exemple l'appel d'un func) qui accède à l'interface utilisateur à partir d'un thread d'arrière-plan.
la source
movq 0x10880ba(%rip), %rsi ; "_wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:"
Lorsque vous essayez de mettre à jour une valeur de champ de texte ou d'ajouter une sous-vue à l'intérieur d'un thread d'arrière-plan, vous pouvez obtenir ce problème. Pour cette raison, vous devez mettre ce type de code dans le thread principal.
Vous devez encapsuler les méthodes qui appellent les mises à jour de l'interface utilisateur avec dispatch_asynch pour obtenir la file d'attente principale. Par exemple:
MODIFIÉ - SWIFT 3:
Maintenant, nous pouvons le faire en suivant le code suivant:
la source
Pour moi, ce message d'erreur provient d'une bannière d'Admob SDK.
J'ai pu suivre l'origine de "WebThread" en définissant un point d'arrêt conditionnel.
Ensuite, j'ai pu me débarrasser du problème en encapsulant la création de la bannière avec:
Je ne sais pas pourquoi cela a aidé car je ne vois pas comment ce code a été appelé à partir d'un thread non principal.
J'espère que cela peut aider n'importe qui.
la source
J'ai eu ce problème depuis la mise à jour vers le SDK iOS 9 lorsque j'appelais un bloc qui effectuait des mises à jour de l'interface utilisateur dans un gestionnaire de fin de demande asynchrone NSURLConnection. Mettre l'appel de bloc dans un dispatch_async à l'aide de dispatch_main_queue a résolu le problème.
Cela a bien fonctionné dans iOS 8.
la source
J'ai eu le même problème parce que j'utilisais
performSelectorInBackground
.la source
Vous ne devez pas modifier l'interface utilisateur en dehors du thread principal! UIKit n'est pas sûr pour les threads, de sorte que le problème ci-dessus et également d'autres problèmes étranges se poseront si vous faites cela. L'application peut même planter.
Donc, pour faire les opérations UIKit, vous devez définir le bloc et le laisser être exécuté sur la file d'attente principale: comme,
la source
De toute évidence, vous effectuez une mise à jour de l'interface utilisateur sur le fil de fond. Impossible de prédire exactement où, sans voir votre code.
Ce sont des situations qui peuvent arriver: -
vous faites peut-être quelque chose sur le fil d'arrière-plan et ne l'utilisez pas. Étant dans la même fonction, ce code est plus facile à repérer.
appelant un func faisant un appel de requête Web sur le thread d'arrière-plan et son gestionnaire d'achèvement appelant un autre func faisant une mise à jour de l'interface utilisateur. pour résoudre ce problème, essayez de vérifier le code dans lequel vous avez mis à jour l'interface utilisateur après l'appel de la demande de Webrequest.
la source
Le problème principal avec "Cette application modifie le moteur de mise en page automatique à partir d'un thread d'arrière-plan" est qu'il semble être enregistré longtemps après que le problème se soit produit, ce qui peut rendre le dépannage très difficile.
J'ai réussi à résoudre le problème en créant trois points d'arrêt symboliques.
Déboguer> Points d'arrêt> Créer un point d'arrêt symbolique ...
Point d'arrêt 1:
Symbole:
-[UIView setNeedsLayout]
État:
!(BOOL)[NSThread isMainThread]
Point d'arrêt 2:
Symbole:
-[UIView layoutIfNeeded]
État:
!(BOOL)[NSThread isMainThread]
Point d'arrêt 3:
Symbole:
-[UIView updateConstraintsIfNeeded]
État:
!(BOOL)[NSThread isMainThread]
Avec ces points d'arrêt, vous pouvez facilement obtenir une pause sur la ligne réelle où vous appelez incorrectement des méthodes d'interface utilisateur sur un thread non principal.
la source
J'ai eu ce problème lors du rechargement des données dans UITableView. L'envoi de rechargement comme suit a résolu le problème pour moi.
la source
J'ai eu le même problème. Il s'avère que j'utilisais
UIAlerts
qui avait besoin de la file d'attente principale. Mais, ils ont été dépréciés .Lorsque j'ai changé le
UIAlerts
enUIAlertController
, je n'ai plus eu le problème et je n'ai plus eu à utiliser dedispatch_async
code. La leçon - faites attention aux avertissements. Ils aident même lorsque vous ne vous y attendez pas.la source
Vous avez déjà la bonne réponse de code de @Mark mais, juste pour partager mes conclusions: Le problème est que vous demandez un changement dans la vue et supposez que cela se produira instantanément. En réalité, le chargement d'une vue dépend des ressources disponibles. Si tout se charge assez rapidement et qu'il n'y a pas de retard, vous ne remarquez rien. Dans les scénarios, où il y a un retard dû au processus occupé, etc., l'application se retrouve dans une situation où elle est censée afficher quelque chose même si elle n'est pas encore prête. Par conséquent, il est conseillé de répartir ces demandes dans des files d'attente asynchrones afin qu'elles soient exécutées en fonction de la charge.
la source
J'ai eu ce problème lorsque j'utilisais TouchID si cela aide quelqu'un d'autre, encapsulez votre logique de réussite qui fait probablement quelque chose avec l'interface utilisateur dans la file d'attente principale.
la source
Cela peut être aussi simple que de définir une valeur de champ / étiquette de texte ou d'ajouter une sous-vue à l'intérieur d'un fil d'arrière-plan, ce qui peut entraîner la modification de la disposition d'un champ. Assurez-vous que tout ce que vous faites avec l'interface ne se produit que dans le thread principal.
Vérifiez ce lien: https://forums.developer.apple.com/thread/7399
la source
J'ai eu le même problème lors de la tentative de mise à jour du message d'erreur dans UILabel dans le même ViewController (cela prend un peu de temps pour mettre à jour les données lorsque vous essayez de le faire avec un codage normal). J'ai utilisé
DispatchQueue
dans Swift 3 Xcode 8 et cela fonctionne.la source
Si vous souhaitez rechercher cette erreur, utilisez la case à cocher principale du vérificateur de threads en cas de problème. La réparation est facile la plupart du temps, en répartissant la ligne problématique dans la file d'attente principale.
la source
Pour moi, le problème était le suivant. Assurez-vous que
performSegueWithIdentifier:
c'est effectué sur le thread principal:la source
Swift 4,
Supposons que si vous appelez une méthode à l'aide d'une file d'attente d'opérations
Et supposons que la fonction searchFavourites est comme,
si vous appelez, tout le code à l'intérieur de la méthode "searchFavourites" sur le thread principal, il donnera toujours une erreur si vous mettez à jour une interface utilisateur.
Alors utilisez la solution,
Pour ce genre de scénario.
la source
Ici, consultez cette ligne dans les journaux
vous pouvez vérifier quelle fonction appelant à partir du thread d'arrière-plan ou où vous appelez la méthode api, vous devez appeler votre fonction à partir du thread principal comme ceci.
Journaux ici
la source
J'ai également rencontré ce problème, voyant une tonne de ces messages et des traces de pile imprimées dans la sortie, lorsque j'ai redimensionné la fenêtre à une taille inférieure à sa valeur initiale. Après avoir longtemps réfléchi au problème, j'ai pensé partager la solution plutôt simple. J'avais une fois activé
Can Draw Concurrently
sur unNSTextView
via IB. Cela indique à AppKit qu'il peut appeler ladraw(_:)
méthode de la vue à partir d'un autre thread. Après l'avoir désactivé, je n'ai plus reçu de message d'erreur. Je n'ai rencontré aucun problème avant la mise à jour vers macOS 10.14 Beta, mais en même temps, j'ai également commencé à modifier le code pour effectuer un travail avec la vue texte.la source