Trying to get current location with using swiftUI. Below code, couldn't initialize with didUpdateLocations delegate.
class GetLocation : BindableObject {
var didChange = PassthroughSubject<GetLocation,Never>()
var location : CLLocation {
didSet {
didChange.send(self)
}
}
init() {}
}
This code below works (Not production ready). Implementing the CLLocationManagerDelegate
works fine and the lastKnownLocation
is updated accordingly.
Don't forget to set the NSLocationWhenInUseUsageDescription
in your Info.plist
class LocationManager: NSObject, CLLocationManagerDelegate, BindableObject {
private let manager: CLLocationManager
var didChange = PassthroughSubject<LocationManager, Never>()
var lastKnownLocation: CLLocation? {
didSet {
didChange.send(self)
}
}
init(manager: CLLocationManager = CLLocationManager()) {
self.manager = manager
super.init()
}
func startUpdating() {
self.manager.delegate = self
self.manager.requestWhenInUseAuthorization()
self.manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations)
lastKnownLocation = locations.last
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
manager.startUpdatingLocation()
}
}
}
As of Xcode 11 beta 4, you will need to change didChange
to willChange
:
var willChange = PassthroughSubject<LocationManager, Never>()
var lastKnownLocation: CLLocation? {
willSet {
willChange.send(self)
}
}
I have written a one-file swift package with usage instructions on https://github.com/himbeles/LocationProvider. It provides a ObservableObject
-type wrapper class for CLLocationManager and its delegate.
There is a published property location
which can directly be used in SwiftUI, as well as a PassthroughSubject that you can subscribe to via Combine. Both update on every didUpdateLocations
event of the CLLocationManager.
It also handles the case where location access has previously been denied: The default behavior is to present the user with a request to enable access in the app settings and a link to go there.
In SwiftUI, use as
import SwiftUI
import LocationProvider
struct ContentView: View {
@ObservedObject var locationProvider : LocationProvider
init() {
locationProvider = LocationProvider()
do {try locationProvider.start()}
catch {
print("No location access.")
locationProvider.requestAuthorization()
}
}
var body: some View {
VStack{
Text("latitude \(locationProvider.location?.coordinate.latitude ?? 0)")
Text("longitude \(locationProvider.location?.coordinate.longitude ?? 0)")
}
}
}