Проверка основного потока: API пользовательского интерфейса вызывается в фоновом потоке: - [UIApplication applicationState]


107

Я использую карты Google в бета-версии Xcode 9, iOS 11.

Я получаю следующее сообщение об ошибке в журнале:

Проверка основного потока: API пользовательского интерфейса вызывается из фонового потока: - [UIApplication applicationState] PID: 4442, TID: 837820, имя потока: com.google.Maps.LabelingBehavior, имя очереди: com.apple.root.default-qos.overcommit , QoS: 21

Почему это происходит, поскольку я почти уверен, что не изменяю какие-либо элементы интерфейса из основного потока в своем коде.

 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)")
        }
    }

1
В mapView(_:didChange)вы диспетчеризацию printзаявления в основную очередь. Вы еще не в основной очереди? Если нет, вам также необходимо отправить animateвызов в основную очередь. Я бы посоветовал вставить несколько dispatchPrecondition(condition: .onQueue(.main))перед этими обновлениями пользовательского интерфейса, на всякий случай.
Роб

Вы сказали: «Я почти уверен, что не изменяю какие-либо элементы интерфейса из основного потока в моем коде». Я полагаю, вы имели в виду «... из любого фонового потока».
Роб

2
Не твоя проблема. Я думаю, это в их конце. Он останавливается на com.google.Maps.LabelingBehavior. У меня такая же проблема.
Tarvo Mäesepp

2
Привет, да, это так, проблема, похоже,
связана

1
@MattBlack Взгляните на этот ответ: stackoverflow.com/a/44392584/5912335
badhanganesh

Ответы:


55

Во-первых, убедитесь, что ваши вызовы карт Google и изменения пользовательского интерфейса вызываются из основного потока.

Вы можете включить дезинфицирующее средство потока, чтобы найти проблемные строки.

Вы можете поместить оскорбительные строки в основной поток следующим образом:

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

Кроме того, обновите текущую версию карт Google. Карты Google пришлось сделать пару обновлений для средства проверки потоков.

На вопрос: «Почему это происходит?» Я думаю, что Apple добавила утверждение для крайнего случая, для которого Google затем пришлось обновить свой модуль.


1
@thibautnoah, вы говорите это потому, что я не сформулировал это как «проблема (проблема) возникает из-за того, что вы используете бета-версию xcode 9 в сочетании с API Google?» Или потому, что вы столкнулись с похожей ошибкой, которая не решена моим ответом?
ScottyBlades

7
Xcode 9 выдвинул на первый план некоторые проблемы с потоками, которые xcode 8, по-видимому, не обнаруживает (связано ли это с настройками xcode или другими вещами, которые необходимо определить). Возвращение к xcode 8 эквивалентно игнорированию ваших проблем с потоками, они все еще существуют и не решены, поэтому это не решение, вы просто зарываете голову в песок и делаете вид, что все в порядке. Если проблема связана с фреймворком, отправьте сообщение о проблеме, чтобы ее можно было исправить.
thibaut noah

Xcode 9 обнаруживает проблемы с потоками, которые xcode 8 не может обнаружить, И Xcode 9 в сочетании с API Google, вероятно, вызывает эту ошибку. Эта ошибка обнаруживается в отладчике из-за нескольких сбоев, И сбои больше не происходят, когда вы переключаетесь обратно на xcode 8.
ScottyBlades

Вы хотите сказать, что средство проверки потоков показывает симптом, а не причину. Я говорю, что бета-версия Xcode 9 является одновременно причиной и коммуникатором симптомов. «сбои больше не происходят, когда вы снова переключаетесь на xcode 8». Есть разница между предупреждениями XCode и фактическими сбоями с показаниями отладчика. Эта ошибка может отображаться как предупреждение ИЛИ сбой. Сбой полностью исчезает при переключении обратно на xcode 8. Бета-версия Xcode 9 не зря называется бета-версией.
ScottyBlades 05

2
Да ... Я думаю, что многим разработчикам iOS трудно понять, что то, что что-то демонстрирует симптом, не означает, что он гарантированно не является причиной. Я также думаю, что трудно согласиться с тем, что Apple могла когда-либо совершить ошибку.
ScottyBlades

157

Иногда сложно найти код пользовательского интерфейса, который не выполняется в основном потоке. Вы можете использовать описанный ниже трюк, чтобы найти и исправить.

  1. Выберите Edit Scheme -> Diagnostics, отметьте Main Thread Checker.

    Xcode 11.4.1

    Щелкните маленькую стрелку рядом со средством проверки основного потока, чтобы создать точку останова средства проверки основного потока. введите описание изображения здесь

    Предыдущий Xcode

    Отметьте «Пауза» по вопросам введите описание изображения здесь

  2. Запустите приложение iOS, чтобы воспроизвести эту проблему. (Xcode должен остановиться на первой проблеме.) введите описание изображения здесь

  3. Оберните код, изменяющий пользовательский интерфейс, в DispatchQueue.main.async {} введите описание изображения здесь


4
Спасибо, сэкономьте мне минут 30.
Orange

10
По какой-то причине, когда я делаю это в Xcode 10.1, я получаю только беспомощный стек вызовов, который я не могу связать со строкой кода: 2018-12-29 19: 46: 56.500629 + 0100 BedtimePrototype [1553: 834478] [сообщает ] Проверка основного потока: API пользовательского интерфейса вызывается в фоновом потоке: - [UIApplication applicationState] PID: 1553, TID: 834478, имя потока: com.apple.CoreMotion.MotionThread, имя очереди: com.apple.root.default-qos. overcommit, QoS: 0
Vilmir

1
У меня также есть стек вызовов, который выглядит беспомощным. С левой стороны он остановился на "com.apple.CoreMotion.MotionThread(23)", затем я также проверяю все другие потоки. Что- Thread 1то привлекло мое внимание: это SVProgressHUD (библиотека просмотра прогресса, которую я использовал). Итак, я знаю, что это вызов SVProgressHUD.show()где-то в целевом контроллере представления. Затем либо оберните каждое появление, DispatchQueue.main.asyncлибо просто закомментируйте, проверьте еще раз, и я выяснил, какой из них проблематичный.
Джон Панг,

2
Я также избавился от предупреждения, закомментировав SVProgressHUD.show. Помещение этого вызова в DispatchQueue.main.async не избавило от предупреждения. Я использую модуль в версии 2.2.5. Эта ветка может помочь лучше понять проблему: github.com/SVProgressHUD/SVProgressHUD/issues/950
Вильмир,

1
Флажка «Приостановить при возникновении проблем» у меня нет в xcode 11.4.1. Изменить: я нашел маленькую стрелку рядом с программой проверки основного потока. Щелчок, который добавляет вам точку останова.
ChrisO

47

Оберните строки кода, которые изменяют пользовательский интерфейс DispatchQueue.main.async {}, чтобы обеспечить их выполнение в основном потоке. В противном случае вы можете вызывать их из фонового потока, в котором модификации пользовательского интерфейса не разрешены. Все такие строки кода должны выполняться из основного потока.


4
да, я уже использовал это, но предупреждение все еще присутствует
MattBlack 06

@Pang, он используется для печати, а не для основного кода пользовательского интерфейса.
Toma

4
@MattBlack попытайтесь обернуть все, что изменяет пользовательский интерфейс, наDispatchQueue.main.async {}
Тома

@ user6603599-Работает как шарм
Sree

3

Перейдите по этой ссылке https://developer.apple.com/documentation/code_diagnostics/main_thread_checker

Для меня это сработало, когда я позвонил из блока.


1
Если вы используете Swift 4+, это лучшее решение, отлично работающее, спасибо, что помогли мне сэкономить время. Я играл с редактором схем, но сейчас лучший вариант - следовать совету Apple и двигаться вперед.
AbuTaareq


-34

Выберите схему -> Диагностика, удалите средство проверки основного потока, после чего предупреждение исчезнет. редактор схем


18
Не думаю, что это хорошая идея. Здесь есть проблема, которую обнаружила программа проверки потоков. Отключение средства проверки потоков позволит не обнаружить эту и будущие проблемы, а в будущем возникнет технический долг, связанный с их устранением.
ablarg

1
На самом деле, я хочу сказать, что мы можем сделать это, используя рендеринг OpenGL es, потому что мы не можем рендерить буфер кадра в основном потоке. право?
L.Peng

1
Ах, значит, если предупреждения не появляется, значит, проблемы не существует?
протестировано

11
"Почему мой детектор дыма продолжает срабатывать?" «Просто извлеките аккумулятор, проблема решена».
Джон Монтгомери

Если предупреждение не появляется, значит, проблемы не существует?
С. Гиссель,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.