iosswiftcore-location

IOS Location - didUpdateLocations not called


I am trying to get location. Issue is that func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) and locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) are never called.

I am asked for permission. I grant it. When I call startLocation second time:

    DispatchQueue.global(qos: .background).async {
        let gpsController = GPSController()
        gpsController.startLocation()
        
        sleep(10)
            DispatchQueue.main.async {
                gpsController.startLocation()
            }
    }

I can see that permission is granted.

import Foundation
import CoreLocation

class GPSController : NSObject, CLLocationManagerDelegate{

let locationManager: CLLocationManager = CLLocationManager()
static var lastLocation : CLLocation? = nil


func startLocation(){
    locationManager.delegate = self
    
    // Sprawdź status usług lokalizacyjnych
    if CLLocationManager.locationServicesEnabled() {
        switch locationManager.authorizationStatus {
        case .notDetermined:
            print("notDetermined")
            locationManager.requestWhenInUseAuthorization()
            break
        case .restricted, .denied:
            print("Denied")
            break
        case .authorizedWhenInUse, .authorizedAlways:
            locationManager.startUpdatingLocation()
            print("authorizedWhenInUse")
        case .authorized:
            print("authorized")
            break
        @unknown default:
            print("@unknown")
            break
        }
    } else {
        print("turn off")
    }
    
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    print("didChangeAuthorization")
    if manager.authorizationStatus == .authorizedWhenInUse {
        locationManager.startUpdatingLocation()
    }
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    print("didChangeAuthorization")
    for currentLocation in locations{
        Loge("Location : \(currentLocation)")
        GPSController.lastLocation = currentLocation
    }
}


func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    print("error")
}    

}


Solution

  • You're putting GPSController inside a global queue, so the scope of the controller does not escape from the queue. After the queue is executed, the controller will be removed. And it no longer listens to that delegate. You can check it by deinit, it will print out after sleep(10).

    class GPSController : NSObject, CLLocationManagerDelegate {
        deinit {
            print("Released")
        }
    }
    

    To resolve: put the GPSController, i.e within a class/controller, to keep a reference.

    class ViewController: UIViewController {
    
        let gpsController = GPSController()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            DispatchQueue.global(qos: .background).async {
                gpsController.startLocation()
    
                sleep(10)
                DispatchQueue.main.async {
                    gpsController.startLocation()
                }
            }
        }
    }
    

    Btw, the delegate should be assigned once, so I would prefer to put it in init

    convenience init() {
        self.init()
        locationManager.delegate = self
    }