133

I am using google maps in Xcode 9 beta, iOS 11.

I am getting an error outputted to the log as follows:

Main Thread Checker: UI API called on a background thread: -[UIApplication applicationState] PID: 4442, TID: 837820, Thread name: com.google.Maps.LabelingBehavior, Queue name: com.apple.root.default-qos.overcommit, QoS: 21

Why would this be occurring as I am almost certain I'm not altering any interface elements from the main thread in my 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)")
        }
    }
MattBlack
  • 3,616
  • 7
  • 32
  • 58
  • 2
    In `mapView(_:didChange)` you are dispatching the `print` statements to the main queue. Are you not already on the main queue? If not, you have to dispatch the `animate` call to the main queue, too. I'd suggest inserting a few `dispatchPrecondition(condition: .onQueue(.main))` before those UI updates, just to make sure. – Rob Jun 26 '17 at 20:50
  • You said "I am almost certain I'm not altering any interface elements from the main thread in my code." I assume you meant "...from any background thread." – Rob Jun 26 '17 at 20:51
  • BTW, you might want to edit your scheme, go to the diagnostics page, and select "pause on issues" underneath "Main Thread Checker". That may help narrow down the source of the problem. – Rob Jun 26 '17 at 20:54
  • 2
    Not your issue. I thing it is at their end. It stops in "com.google.Maps.LabelingBehavior". I have the same poblem. – Tarvo Mäesepp Jun 26 '17 at 21:59
  • I spent ages trying to work it out, but I would agree with your conclusion. Thanks though @Rob ! – MattBlack Jun 26 '17 at 22:00
  • @MattBlack, I'm super curious, did my answer solve the problem for you? I encountered this issue multilpe times, if it doesn't solve it for you, then I would have more data on this type of bug. – ScottyBlades Aug 28 '17 at 09:48
  • 2
    Hi, yes it did, the issue seems to lie with google, hopefully they will release an updated version soon – MattBlack Aug 29 '17 at 12:44
  • 1
    @MattBlack Take a look at this answer: https://stackoverflow.com/a/44392584/5912335 – badhanganesh Sep 21 '17 at 22:07
  • I had this issue as well with the manually installed version of Google Maps. Once I switched to the CocoaPods managed version, the error went away. Assuming Google fixed that bug in more recent versions of their framework. – wildcat12 Oct 06 '18 at 14:42

6 Answers6

177

It's hard to find the UI code which is not executed in main thread sometimes. You can use the trick below to locate it and fix it.

  1. Choose Edit Scheme -> Diagnostics, tick Main Thread Checker.

    Xcode 11.4.1

    Click the small arrow next to the Main Thread Checker to create a Main Thread Checker breakpoint. enter image description here

    Previous Xcode

    Tick on Pause on issues. enter image description here

  2. Run your iOS application to reproduce this issue. (Xcode should pause on the first issue.) enter image description here

  3. Wrap the code that modify the UI in DispatchQueue.main.async {} enter image description here

webcpu
  • 3,174
  • 2
  • 24
  • 17
  • Tried same but it is not pausing at the line of issue, Any other solution? – IamDev Jul 10 '18 at 07:08
  • It's hard to tell. I just simply rely on Main Thread Checker, and I only solve the problems which Main Thread Checker complains and it's good enough for me. – webcpu Jul 11 '18 at 07:59
  • 10
    For some reason, when I do that in Xcode 10.1, I only get a callstack that is helpless and that I cannot relate to a code line: 2018-12-29 19:46:56.500629+0100 BedtimePrototype[1553:834478] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication applicationState] PID: 1553, TID: 834478, Thread name: com.apple.CoreMotion.MotionThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 0 – Vilmir Dec 29 '18 at 18:51
  • 1
    I also got a call stack that look helpless. On left hand side it stopped at `"com.apple.CoreMotion.MotionThread(23)"`, then I check all other threads as well. In `Thread 1` something caught my attention: it is SVProgressHUD (a progress view library I used). So, I know it's a call to `SVProgressHUD.show()` somewhere in target view controller. Then either wrap each appearance with `DispatchQueue.main.async` or simply comment out, test again and I found out which one is problematic. – John Pang Feb 20 '19 at 14:22
  • @JohnPang Weird, exact same thing happened here but with MBProgressHUD. Thanks for the tip! – Robbie Trencheny Apr 19 '19 at 05:16
  • 2
    I also got rid of the warning by commenting out SVProgressHUD.show. Wrapping this call into a DispatchQueue.main.async did not get rid of the warning. I use the pod in v2.2.5 This thread can help understanding the problem better: https://github.com/SVProgressHUD/SVProgressHUD/issues/950 – Vilmir Apr 20 '19 at 19:30
  • 2
    The "Pause on Issues" checkbox isn't there for me in xcode 11.4.1. Edit: I found a small arrow next to the Main Thread Checker. Clicking that adds a breakpoint for you. – ChrisO May 19 '20 at 14:04
  • 2
    This appears to have disappeared in Xcode 12. Does anyone know where it moved? – below Sep 30 '20 at 15:36
  • In XCode v13.0 this option (small arrow) mentioned in Step#1 above isn't available: Click the small arrow next to the Main Thread Checker to create a Main Thread Checker. Instead, a breakpoint can be added directly: Navigator (typically left pane) -> Breakpoint navigator in top bar within the pane -> ‘+’ in bottom bar within the pane to ‘Create a breakpoint’ -> Type: Main Thread Checker. – Hasaa2 Khidala Oct 15 '21 at 05:01
87

First, make sure your invocations of google maps and ui changes are called from the main thread.

You can enable Thread Sanitizer option in Xcode using below steps:

Screenshot

You can put offending lines on the main thread with the following:

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

Also, update your current version of google maps. Google maps had to make a couple of updates for the thread checker.

For the question: "Why would this be occurring?" I think Apple added an assertion for an edge case which Google then had to update their pod for.

ScottyBlades
  • 12,189
  • 5
  • 77
  • 85
  • 1
    @thibautnoah, are you saying that because I did not phrase it as "it (the problem) is occuring because you are using xcode 9 beta in combination with Google's API?" Or because you are facing a similar bug which is not solved by my answer? – ScottyBlades Sep 04 '17 at 10:42
  • 7
    Xcode 9 highlighted some threading issues which xcode 8 apparently does not detect (whether it is due to xcode settings or another thing is to be determined). Switching back to xcode 8 is equivalent to ignoring your threading issues, they are still there and are not solved, thus it is not a solution, you are just burying your head in the sand and pretending everything is ok. If the issue is coming from a framework please submit an issue so that it can be fixed. – thibaut noah Sep 04 '17 at 12:01
  • Xcode 9 detects threading issues which xcode 8 does not proport to detect, AND Xcode 9 in combination with Google's API likely does cause this bug. This bug is sited in the debugger for multiple crashes AND the crashes no longer happen when you switch back to xcode 8. – ScottyBlades Sep 04 '17 at 18:34
  • You're point is that the thread checker is showing the symptom not the cause. I'm saying Xcode 9 beta is both the cause AND the symptom communicator. "the crashes no longer happen when you switch back to xcode 8". There is a difference between XCode warnings and actual crashes with debugger readouts. This error can show up as a warning OR a crash. The crashing goes away entirely when switching back to xcode 8. Xcode 9 beta is called beta for a good reason. – ScottyBlades Sep 05 '17 at 08:10
  • Not at all, i'm saying that xcode 9 has a better checking of threads (also a new swift api since it ships for ios 11 with swift 3.3 and swift 4, and not just threads actually). Not having the issue in xcode 8 does NOT mean the issue is not there because it is ! It will simply be obvious with xcode 9 while on xcode 8 you will not be aware that there actually is an issue. The root cause of the problem here is either your code or google framework, NOT xcode 9. But it is your code and if you decide to ignore the issue that is up to you, i've said my piece – thibaut noah Sep 05 '17 at 09:06
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153666/discussion-between-thibaut-noah-and-scottyblades). – thibaut noah Sep 05 '17 at 09:06
  • 2
    Yes...I think its hard for many ios developers to see that just because something is showing the symptom, doesn't mean it is gauranteed not to be the the cause as well. I think its also hard to accept that Apple might have ever made a mistake. – ScottyBlades Sep 20 '17 at 18:35
  • Apple made a lot of mistakes, that's not the point here and you know it. Doesn't mean it's not the cause, but blatantly ignoring the fact that there is a high chance that there is indeed a threading issue in the code is like i said before buying your head in the sand. Thought i made myself clear before. – thibaut noah Sep 25 '17 at 11:01
52

Wrap the lines of code that modify the UI in DispatchQueue.main.async {} in order to make sure they execute on the main thread. Otherwise, you may be calling them from a background thread, where UI modifications are not allowed. All such lines of code must be executed from the main thread.

Toma
  • 2,764
  • 4
  • 25
  • 44
4

Refer this link https://developer.apple.com/documentation/code_diagnostics/main_thread_checker

For me this worked when I called from block.

  • 1
    If you are using Swift 4+, this is the best solution works perfect, thank you for helping me to save my time. I have played with Scheme Editor but following Apple advice is the best option now and moving forward. – AbuTaareq Jan 29 '18 at 18:30
  • 2
    Unfortunately that is now a dead link. – Marcy Sep 14 '20 at 06:23
0

I think the solution is already given, For my issue is Keyboard on the way.

UIKeyboardTaskQueue may only be called from the main thread

gamal
  • 1,587
  • 2
  • 21
  • 43
-44

Choose scheme -> Diagnotics, remove main thread checker, then the warning will disappear. scheme editor

L.Peng
  • 1
  • 5
  • 22
    I don't think this is a good idea. There is a problem here that the thread checker has discovered. Disabling thread checker will allow this and future problems to go undiscovered, and cause future technical debt to be incurred fixing the issues. – ablarg Aug 25 '17 at 19:19
  • 1
    Actually, my point is we can do this when we use OpenGL es rendering, because we can't render frame buffer in main thread. right? – L.Peng Aug 29 '17 at 12:50
  • 3
    Ah, so if the waring doesn't appear the problem doesn't exists? – turingtested Nov 24 '17 at 13:26
  • 18
    "Why does my smoke detector keep going off?" "Just remove the battery, problem solved." – John Montgomery Oct 04 '18 at 18:52
  • If the warning doesn't appear the problem doesn't exists? – S. Gissel Jan 06 '20 at 11:40