I have this silly issue where I have been debugging for a whole day:
I implemented LocationManager class to retrieve user’s coordinate, it worked last night. Then suddenly it stopped working today, I ran locationManager.startUpdatingLocation()
but locationManager
delegates never got fired, no result nor error. The class is a singleton so it stayed there without being destroyed, I checked locationManager.delegate
and it refers my class LocationManager
(not nil)
I have read almost every post about CLLocationManager and I’m desperated.
Here is my Info.plist:
<key>NSWidgetUsesLocation</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Enable Weather for Power Users</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Enable Weather for Power Users</string>
and LocationManager.swift
import Foundation
import CoreLocation
// Usage
// LocationManager.Instance.getCoordinateString(() { coordinatesString
// print("Current coordinates string: \(coordinatesString!)")
//)
class LocationManager: NSObject, CLLocationManagerDelegate {
static let Instance = LocationManager()
private var locationManager = CLLocationManager()
private var authorizeCompletion: (() -> Void)?
private var updateCompletion: ((_ coordinateString: String?) -> Void)?
private override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer
}
public func requestPermission(completion: @escaping () -> Void) {
if status != .notDetermined {
completion()
return
}
authorizeCompletion = completion
locationManager.requestAlwaysAuthorization()
}
public var status: CLAuthorizationStatus {
get {
return locationManager.authorizationStatus
}
}
func getCoordinateString(completion: @escaping (_ coordinateString: String?) -> Void) {
print("LocationManager.getCoordinateString() \(status)", locationManager.delegate)
if status == .denied || status == .restricted {
// print("LocationManager.locationManager(): ERROR Permission:", status)
completion(nil)
return
}
if status == .notDetermined {
completion(nil) // Temporary return basic weather
requestPermission(completion: { [self] in
updateCompletion = completion
locationManager.startUpdatingLocation()
// locationManager.requestLocation()
})
return
}
updateCompletion = completion
locationManager.startUpdatingLocation()
}
// MARK: CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print("LocationManager.locationManager(): Authorization completed", status)
authorizeCompletion?()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("LocationManager.locationManager(): didUpdateLocations")
guard let location = locations.last else {
print("LocationManager.locationManager(): ERROR No coodinate found")
updateCompletion?(nil)
updateCompletion = nil
return
}
// Stop updating location after the first result
locationManager.stopUpdatingLocation()
let latitude = String(format: "%.4f", location.coordinate.latitude)
let longitude = String(format: "%.4f", location.coordinate.longitude)
let result = "\(latitude),\(longitude)"
// Call completion handler if it's set
updateCompletion?(result)
updateCompletion = nil
print("LocationManager.locationManager(): Coordinate \(result)")
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("LocationManager.locationManager(): ERROR \(error.localizedDescription)")
updateCompletion?(nil)
updateCompletion = nil
locationManager.stopUpdatingLocation()
}
}
I have tested:
- On iOS Simulators
- On all real devices through Testflight & Xcode debugging installs
- Even with my code reverted.
So far I have tried to create a clean project and put my LocationManager.swift and it’s working perfectly!? on iOS simulator
Another funny note that even without Info.plist keys being added, the “clean project” I tested still returns error:
LocationManager.locationManager(): ERROR The operation couldn’t be completed. (kCLErrorDomain error 1.)