Verificador de thread principal: UI API chamada em um thread de segundo plano: - [UIApplication applicationState]

107

Estou usando o google maps no Xcode 9 beta, iOS 11.

Estou recebendo um erro no log da seguinte maneira:

Verificador de thread principal: UI API chamada em um thread de segundo plano: - [UIApplication applicationState] PID: 4442, TID: 837820, Nome do thread: com.google.Maps.LabelingBehavior, Nome da fila: com.apple.root.default-qos.overcommit , QoS: 21

Por que isso estaria ocorrendo, já que tenho quase certeza de que não estou alterando nenhum elemento de interface do thread principal em meu código.

 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)")
        }
    }
MattBlack
fonte
1
Em mapView(_:didChange)você está despachando as printinstruções para a fila principal. Você ainda não está na fila principal? Do contrário, você também deve enviar a animatechamada para a fila principal. Eu sugiro inserir alguns dispatchPrecondition(condition: .onQueue(.main))antes dessas atualizações da IU, apenas para ter certeza.
Rob
Você disse: "Tenho quase certeza de que não estou alterando nenhum elemento de interface do thread principal em meu código". Presumo que você quis dizer "... de qualquer thread de fundo."
Rob
2
Não é o seu problema. Acho que está no fim deles. Ele pára em "com.google.Maps.LabelingBehavior". Eu tenho o mesmo problema.
Tarvo Mäesepp
2
Olá, sim, o problema parece ser do Google. Esperamos que eles
lançem
1
@MattBlack Dê uma olhada nesta resposta: stackoverflow.com/a/44392584/5912335
badhanganesh

Respostas:

53

Primeiro, certifique-se de que suas invocações de mapas do Google e mudanças de interface do usuário sejam chamadas a partir do tópico principal.

Você pode habilitar o Thread Sanitizer para localizar linhas problemáticas.

Você pode colocar linhas ofensivas no tópico principal com o seguinte:

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

Além disso, atualize sua versão atual do google maps. O Google Maps teve que fazer algumas atualizações para o verificador de threads.

Para a pergunta: "Por que isso estaria ocorrendo?" Acho que a Apple acrescentou uma afirmação para um caso extremo para o qual o Google teve que atualizar seu pod.

ScottyBlades
fonte
1
@thibautnoah, você está dizendo isso porque eu não disse isso como "(o problema) está ocorrendo porque você está usando o xcode 9 beta em combinação com a API do Google?" Ou porque você está enfrentando um bug semelhante que não é resolvido pela minha resposta?
ScottyBlades
7
O Xcode 9 destacou alguns problemas de threading que o xcode 8 aparentemente não detecta (seja devido às configurações do xcode ou outra coisa a ser determinada). Voltar para o xcode 8 é equivalente a ignorar seus problemas de encadeamento, eles ainda estão lá e não foram resolvidos, portanto não é uma solução, você está apenas enterrando a cabeça na areia e fingindo que está tudo bem. Se o problema vier de uma estrutura, envie-o para que seja corrigido.
thibaut noah
O Xcode 9 detecta problemas de threading que o xcode 8 não tem proporção para detectar E o Xcode 9 em combinação com a API do Google provavelmente causa esse bug. Este bug está localizado no depurador para falhas múltiplas E as falhas não acontecem mais quando você volta para o xcode 8.
ScottyBlades
O que você quer dizer é que o verificador de thread está mostrando o sintoma, não a causa. Estou dizendo que o Xcode 9 beta é tanto a causa quanto o comunicador de sintomas. "as falhas não acontecem mais quando você volta para o xcode 8". Há uma diferença entre os avisos do XCode e as falhas reais com as leituras do depurador. Este erro pode aparecer como um aviso OU uma falha. O travamento desaparece completamente ao voltar para o xcode 8. O Xcode 9 beta é chamado de beta por um bom motivo.
ScottyBlades
2
Sim ... Eu acho que é difícil para muitos desenvolvedores de iOS verem que só porque algo está mostrando o sintoma, não significa que é garantido que não seja a causa também. Acho também difícil aceitar que a Apple possa ter cometido um erro.
ScottyBlades de
156

É difícil encontrar o código da IU que às vezes não é executado no thread principal. Você pode usar o truque abaixo para localizá-lo e corrigi-lo.

  1. Escolha Editar esquema -> Diagnóstico, marque Verificador de thread principal.

    Xcode 11.4.1

    Clique na pequena seta ao lado do Main Thread Checker para criar um ponto de interrupção do Main Thread Checker. insira a descrição da imagem aqui

    Xcode anterior

    Marque em Pausa nos problemas. insira a descrição da imagem aqui

  2. Execute seu aplicativo iOS para reproduzir este problema. (O Xcode deve pausar na primeira edição.) insira a descrição da imagem aqui

  3. Envolva o código que modifica a IU em DispatchQueue.main.async {} insira a descrição da imagem aqui

UnchartedWorks
fonte
4
Obrigado, economize-me talvez 30 minutos.
Laranja
10
Por alguma razão, quando faço isso no Xcode 10.1, recebo apenas uma pilha de chamadas indefesa e que não posso relacionar a uma linha de código: 2018-12-29 19: 46: 56.500629 + 0100 BedtimePrototype [1553: 834478] [relatórios ] Main Thread Checker: UI API chamada em um thread em segundo plano: - [UIApplication applicationState] PID: 1553, TID: 834478, Nome do thread: com.apple.CoreMotion.MotionThread, Nome da fila: com.apple.root.default-qos. overcommit, QoS: 0
Vilmir
1
Eu também tenho uma pilha de chamadas que parece indefesa. No lado esquerdo, parou em"com.apple.CoreMotion.MotionThread(23)" , então eu verifico todos os outros tópicos também. Em Thread 1algo me chamou a atenção: é SVProgressHUD (uma biblioteca de vista o progresso que eu usei). Então, eu sei que é uma chamada para SVProgressHUD.show()algum lugar no controlador de exibição de destino. Em seguida, envolva cada aparência com DispatchQueue.main.asyncou simplesmente comente, teste novamente e descobri qual é o problema.
John Pang de
2
Eu também me livrei do aviso comentando SVProgressHUD.show. Encapsular essa chamada em um DispatchQueue.main.async não eliminou o aviso. Eu uso o pod na v2.2.5. Este tópico pode ajudar a entender melhor o problema: github.com/SVProgressHUD/SVProgressHUD/issues/950
Vilmir
1
A caixa de seleção "Pause on Issues" não está lá para mim no xcode 11.4.1. Edit: Encontrei uma pequena seta ao lado do Main Thread Checker. Clicar em que adiciona um ponto de interrupção para você.
ChrisO
47

Envolva as linhas de código que modificam a IU DispatchQueue.main.async {}para garantir que sejam executadas no thread principal. Caso contrário, você pode chamá-los de um thread de segundo plano, onde modificações de IU não são permitidas. Todas essas linhas de código devem ser executadas a partir do thread principal.

Dimitrie-Toma Furdui
fonte
4
sim, já usei isso, mas o aviso ainda está presente
MattBlack
@Pang, é usado para imprimir coisas, não para o código da IU principal.
Dimitrie-Toma Furdui
4
@MattBlack tenta envolver todas as coisas que modificam a IU noDispatchQueue.main.async {}
Dimitrie-Toma Furdui
@ user6603599-Funciona como um encanto
Sree
3

Consulte este link https://developer.apple.com/documentation/code_diagnostics/main_thread_checker

Para mim, isso funcionou quando liguei do bloco.

Krishna Chaitanya Bandaru
fonte
1
Se você estiver usando o Swift 4+, esta é a melhor solução funciona perfeitamente, obrigado por me ajudar a economizar meu tempo. Eu joguei com o Scheme Editor, mas seguir os conselhos da Apple é a melhor opção agora e no futuro.
AbuTaareq
-34

Escolha o esquema -> Diagnótico, remova o verificador da linha de execução principal e o aviso desaparecerá. editor de esquema

L.Peng
fonte
18
Não acho que seja uma boa ideia. Há um problema aqui que o verificador de threads descobriu. Desativar o verificador de tópicos permitirá que este e os problemas futuros não sejam descobertos, e fará com que problemas técnicos futuros sejam incorridos para corrigir os problemas.
ablarg
1
Na verdade, meu ponto é que podemos fazer isso quando usamos a renderização OpenGL es, porque não podemos renderizar o buffer de quadro no thread principal. certo?
L.Peng
1
Ah, então se o aviso não aparecer o problema não existe?
testado em
11
"Por que meu detector de fumaça continua disparando?" "Basta remover a bateria, problema resolvido."
John Montgomery,
Se o aviso não aparecer, o problema não existe?
S. Gissel