Vérificateur de thread principal: API d'interface utilisateur appelée sur un thread d'arrière-plan: - [UIApplication applicationState]

107

J'utilise Google Maps dans Xcode 9 beta, iOS 11.

Je reçois une erreur dans le journal comme suit:

Vérificateur de thread principal: API d'interface utilisateur appelée sur un thread d'arrière-plan: - [UIApplication applicationState] PID: 4442, TID: 837820, nom de thread: com.google.Maps.LabelingBehavior, nom de file d'attente: com.apple.root.default-qos.overcommit , QoS: 21

Pourquoi cela se produirait-il alors que je suis presque certain que je ne modifie aucun élément d'interface du thread principal de mon code.

 override func viewDidLoad() {

    let locationManager = CLLocationManager()


    locationManager.requestAlwaysAuthorization()


    locationManager.requestWhenInUseAuthorization()

        if CLLocationManager.locationServicesEnabled() {

            locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
            locationManager.startUpdatingLocation()
        }

      viewMap.delegate = self

     let camera = GMSCameraPosition.camera(withLatitude: 53.7931183329367, longitude: -1.53649874031544, zoom: 17.0)


        viewMap.animate(to: camera)


    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let locValue:CLLocationCoordinate2D = manager.location!.coordinate
        print("locations = \(locValue.latitude) \(locValue.longitude)")
    }

    func mapView(_ mapView: GMSMapView, willMove gesture: Bool) {


    }

    func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {

        if(moving > 1){
            moving = 1
        UIView.animate(withDuration: 0.5, delay: 0, animations: {

            self.topBarConstraint.constant = self.topBarConstraint.constant + (self.topBar.bounds.height / 2)

            self.bottomHalfConstraint.constant = self.bottomHalfConstraint.constant + (self.topBar.bounds.height / 2)

            self.view.layoutIfNeeded()
        }, completion: nil)
    }
         moving = 1
    }


    // Camera change Position this methods will call every time
    func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
        moving = moving + 1
        if(moving == 2){


            UIView.animate(withDuration: 0.5, delay: 0, animations: {


                self.topBarConstraint.constant = self.topBarConstraint.constant - (self.topBar.bounds.height / 2)

                self.bottomHalfConstraint.constant = self.bottomHalfConstraint.constant - (self.topBar.bounds.height / 2)


                self.view.layoutIfNeeded()
            }, completion: nil)
        }
        DispatchQueue.main.async {

            print("Moving: \(moving) Latitude: \(self.viewMap.camera.target.latitude)")
            print("Moving: \(moving)  Longitude: \(self.viewMap.camera.target.longitude)")
        }
    }
Noir mat
la source
1
Dans mapView(_:didChange)vous distribuez les printinstructions à la file d'attente principale. N'êtes-vous pas déjà dans la file d'attente principale? Sinon, vous devez également envoyer l' animateappel vers la file d'attente principale. Je suggérerais d'en insérer quelques-unes dispatchPrecondition(condition: .onQueue(.main))avant ces mises à jour de l'interface utilisateur, juste pour être sûr.
Rob
Vous avez dit "Je suis presque certain que je ne modifie aucun élément d'interface du thread principal de mon code." Je suppose que vous vouliez dire "... depuis n'importe quel fil de discussion".
Rob
2
Pas votre problème. Je pense que c'est à leur fin. Il s'arrête dans "com.google.Maps.LabelingBehavior". J'ai le même poblème.
Tarvo Mäesepp
2
Salut, oui, le problème semble résider dans Google, j'espère qu'ils publieront bientôt une version mise à jour
MattBlack
1
@MattBlack Jetez un œil à cette réponse: stackoverflow.com/a/44392584/5912335
badhanganesh

Réponses:

54

Tout d'abord, assurez-vous que vos appels de google maps et de modifications de l'interface utilisateur sont appelés à partir du fil de discussion principal.

Vous pouvez activer Thread Sanitizer pour trouver les lignes incriminées.

Vous pouvez mettre des lignes offensantes sur le fil principal avec les éléments suivants:

DispatchQueue.main.async {
    //Do UI Code here. 
    //Call Google maps methods.
}

Mettez également à jour votre version actuelle de google maps. Google Maps a dû faire quelques mises à jour pour le vérificateur de fil.

Pour la question: "Pourquoi cela se produirait-il?" Je pense qu'Apple a ajouté une assertion pour un cas de pointe pour lequel Google a ensuite dû mettre à jour son pod.

ScottyBlades
la source
1
@thibautnoah, est-ce que vous dites cela parce que je ne l'ai pas exprimé comme "le problème se produit parce que vous utilisez xcode 9 beta en combinaison avec l'API de Google?" Ou parce que vous êtes confronté à un bug similaire qui n'est pas résolu par ma réponse?
ScottyBlades
7
Xcode 9 a mis en évidence certains problèmes de threading que xcode 8 ne détecte apparemment pas (que cela soit dû à des paramètres xcode ou à une autre chose à déterminer). Revenir à xcode 8 équivaut à ignorer vos problèmes de threading, ils sont toujours là et ne sont pas résolus, donc ce n'est pas une solution, vous vous enfoncez simplement la tête dans le sable et prétendez que tout va bien. Si le problème provient d'un framework, veuillez soumettre un problème afin qu'il puisse être résolu.
thibaut noah
Xcode 9 détecte les problèmes de threading que xcode 8 ne permet pas de détecter, ET Xcode 9 en combinaison avec l'API de Google est probablement à l'origine de ce bogue. Ce bogue est situé dans le débogueur pour plusieurs plantages ET les plantages ne se produisent plus lorsque vous revenez au xcode 8.
ScottyBlades
Vous dites que le vérificateur de thread montre le symptôme et non la cause. Je dis que Xcode 9 beta est à la fois la cause ET le communicateur de symptômes. "les plantages ne se produisent plus lorsque vous revenez à xcode 8". Il existe une différence entre les avertissements XCode et les plantages réels avec les lectures du débogueur. Cette erreur peut apparaître comme un avertissement OU un plantage. Le plantage disparaît entièrement lors du retour à xcode 8. Xcode 9 beta est appelé beta pour une bonne raison.
ScottyBlades
2
Oui ... Je pense que c'est difficile pour de nombreux développeurs iOS de voir que ce n'est pas parce que quelque chose montre le symptôme qu'il est garanti que ce n'est pas la cause. Je pense qu'il est également difficile d'accepter qu'Apple ait jamais commis une erreur.
ScottyBlades
156

Il est parfois difficile de trouver le code d'interface utilisateur qui n'est pas exécuté dans le thread principal. Vous pouvez utiliser l'astuce ci-dessous pour le localiser et le réparer.

  1. Choisissez Edit Scheme -> Diagnostics, cochez Main Thread Checker.

    Xcode 11.4.1

    Cliquez sur la petite flèche en regard du vérificateur de thread principal pour créer un point d'arrêt du vérificateur de thread principal. entrez la description de l'image ici

    Xcode précédent

    Cochez Pause sur les problèmes. entrez la description de l'image ici

  2. Exécutez votre application iOS pour reproduire ce problème. (Xcode devrait faire une pause sur le premier problème.) entrez la description de l'image ici

  3. Enveloppez le code qui modifie l'interface utilisateur dans DispatchQueue.main.async {} entrez la description de l'image ici

UnchartedWorks
la source
4
Merci, économisez-moi peut-être 30 minutes.
Orange
10
Pour une raison quelconque, lorsque je fais cela dans Xcode 10.1, je reçois uniquement une pile d'appels impuissante et que je ne peux pas associer à une ligne de code: 2018-12-29 19: 46: 56.500629 + 0100 BedtimePrototype [1553: 834478] [rapports ] Vérificateur de thread principal: API d'interface utilisateur appelée sur un thread d'arrière-plan: - [UIApplication applicationState] PID: 1553, TID: 834478, nom de thread: com.apple.CoreMotion.MotionThread, nom de file d'attente: com.apple.root.default-qos. overcommit, QoS: 0
Vilmir
1
J'ai aussi une pile d'appels qui semble impuissante. Sur le côté gauche, il s'est arrêté "com.apple.CoreMotion.MotionThread(23)", puis je vérifie également tous les autres threads. Dans Thread 1quelque chose a attiré mon attention: c'est SVProgressHUD (une bibliothèque de vue de progression que j'ai utilisée). Donc, je sais que c'est un appel à SVProgressHUD.show()quelque part dans le contrôleur de vue cible. Ensuite, enveloppez chaque apparition avec DispatchQueue.main.asyncou commentez simplement, testez à nouveau et j'ai découvert laquelle est problématique.
John Pang
2
Je me suis également débarrassé de l'avertissement en commentant SVProgressHUD.show. L'emballage de cet appel dans un DispatchQueue.main.async n'a pas éliminé l'avertissement. J'utilise le pod dans la v2.2.5 Ce fil peut aider à mieux comprendre le problème: github.com/SVProgressHUD/SVProgressHUD/issues/950
Vilmir
1
La case à cocher «Pause sur les problèmes» n'est pas là pour moi dans xcode 11.4.1. Edit: J'ai trouvé une petite flèche à côté du vérificateur de fil principal. En cliquant dessus, vous ajoutez un point d'arrêt.
ChrisO
47

Enveloppez les lignes de code qui modifient l'interface utilisateur DispatchQueue.main.async {}afin de vous assurer qu'elles s'exécutent sur le thread principal. Sinon, vous pouvez les appeler à partir d'un thread d'arrière-plan, où les modifications de l'interface utilisateur ne sont pas autorisées. Toutes ces lignes de code doivent être exécutées à partir du thread principal.

Toma
la source
4
oui je l'ai déjà utilisé mais l'avertissement est toujours présent
MattBlack
@Pang, il est utilisé pour imprimer des choses, pas pour le code principal de l'interface utilisateur.
Toma
4
@MattBlack essaie d'envelopper toutes les choses qui modifient l'interface utilisateur sur leDispatchQueue.main.async {}
Toma
@ user6603599-Fonctionne comme un charme
Sree
3

Reportez-vous à ce lien https://developer.apple.com/documentation/code_diagnostics/main_thread_checker

Pour moi, cela a fonctionné lorsque j'ai appelé du bloc.

Krishna Chaitanya Bandaru
la source
1
Si vous utilisez Swift 4+, c'est la meilleure solution qui fonctionne parfaitement, merci de m'aider à gagner du temps. J'ai joué avec l'éditeur de schéma, mais suivre les conseils d'Apple est la meilleure option pour le moment et pour l'avenir.
AbuTaareq
-34

Choisissez schéma -> Diagnostics, supprimez le vérificateur de thread principal, puis l'avertissement disparaîtra. éditeur de schéma

L.Peng
la source
18
Je ne pense pas que ce soit une bonne idée. Il y a un problème ici que le vérificateur de thread a découvert. La désactivation du vérificateur de threads permettra à ce problème et aux futurs problèmes de ne pas être découverts, et entraînera de futures dettes techniques pour résoudre les problèmes.
ablarg
1
En fait, ce que je veux dire, c'est que nous pouvons le faire lorsque nous utilisons le rendu OpenGL es, car nous ne pouvons pas rendre le frame buffer dans le thread principal. droite?
L.Peng
1
Ah, si l'avertissement n'apparaît pas, le problème n'existe pas?
testée
11
"Pourquoi mon détecteur de fumée continue-t-il de s'éteindre?" "Retirez simplement la batterie, le problème est résolu."
John Montgomery
Si l'avertissement n'apparaît pas, le problème n'existe pas?
S. Gissel le