How to Get Current Location with Swiftui

How to get Current Location using SwiftUI, without ViewControllers?

You could create a StateObject of your LocationManager by implementing the ObservableObject protocol.

With the @Published attribute you can create a publisher object which notify the observers (your view, in this case) when something changes inside that object.

That's why in my LocationManager I added the @Published attribute to those var:

  1. locationStatus: CLAuthorizationStatus? it contains the value received from didChangeAuthorization delegate method
  2. lastLocation: CLLocation? it contains the last location calculated by the didUpdateLocations delegate method

LocationManager

import Foundation
import CoreLocation
import Combine

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {

private let locationManager = CLLocationManager()
@Published var locationStatus: CLAuthorizationStatus?
@Published var lastLocation: CLLocation?

override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}



var statusString: String {
guard let status = locationStatus else {
return "unknown"
}

switch status {
case .notDetermined: return "notDetermined"
case .authorizedWhenInUse: return "authorizedWhenInUse"
case .authorizedAlways: return "authorizedAlways"
case .restricted: return "restricted"
case .denied: return "denied"
default: return "unknown"
}
}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
locationStatus = status
print(#function, statusString)
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
lastLocation = location
print(#function, location)
}
}

View

In your view you need to create only an instance of LocationManager marked as @StateObject

import SwiftUI

struct MyView: View {

@StateObject var locationManager = LocationManager()

var userLatitude: String {
return "\(locationManager.lastLocation?.coordinate.latitude ?? 0)"
}

var userLongitude: String {
return "\(locationManager.lastLocation?.coordinate.longitude ?? 0)"
}

var body: some View {
VStack {
Text("location status: \(locationManager.statusString)")
HStack {
Text("latitude: \(userLatitude)")
Text("longitude: \(userLongitude)")
}
}
}
}

struct MyView_Previews: PreviewProvider {
static var previews: some View {
MyView()
}
}

Sample Image

SwiftUI: How to get the current location of user?

Yes, it's been deprecated in favour of using a property of the same name instead of a function, try it without the parentheses...

if manager.authorizationStatus == .authorizedWhenInUse {

How to get Current Location with SwiftUI?

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, ObservableObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
var lastKnownLocation: CLLocation?

func startUpdating() {
manager.delegate = self
manager.requestWhenInUseAuthorization()
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()
}
}
}

Retrieve user current location using SwiftUI and MapKit

Create instance of CLLocationManager:

var locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()

then get the details:

var currentLocation: CLLocation!

if( CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
CLLocationManager.authorizationStatus() == .authorizedAlways){

currentLocation = locManager.location

}

then to get longitude or latitude:

let longitude = currentLocation.coordinate.longitude
let latitude = currentLocation.coordinate.latitude

If you'd like to perform it inside a swiftUI view script, create instance:

@ObservedObject var locationManager = LocationManager()

Get them separately:

var userLatitude: String {
return "\(locationManager.lastLocation?.coordinate.latitude ?? 0)"

var userLongitude: String {
return "\(locationManager.lastLocation?.coordinate.longitude ?? 0)"

Automatically include user’s current location in a SMS (Swift)

You are mixing the code of UIKit and SwiftUI. First You have to create location Manager class and then assign that class to StateObject and use it in SWiftUI View.

Use following as Location manager : -

       class LocationManager: NSObject, ObservableObject,CLLocationManagerDelegate {
let manager = CLLocationManager()

@Published var location: CLLocationCoordinate2D?

override init() {
super.init()
manager.delegate = self
}

func requestLocation() {
manager.requestLocation()
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
location = locations.first?.coordinate
}
}

Now Initialize locationManager View Do as Following : -

       @StateObject var locationManager = LocationManager()

Then request location using following code whenever you want to access user location : -

       locationManager.requestLocation()

And now you can access location Using following : -

       locationManager.location.latitude 

or

       locationManager.location.longitude

SwiftUI mapkit set region to user's current location

Here's one possible solution to this:

final class LocationManager: NSObject, ObservableObject {
@Published var location: CLLocation?
@Published var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 38.898150, longitude: -77.034340),
span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
)
private var hasSetRegion = false

private let locationManager = CLLocationManager()

override init() {
super.init()

self.locationManager.delegate = self

self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.distanceFilter = kCLDistanceFilterNone
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}

extension LocationManager: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
self.location = location

if !hasSetRegion {
self.region = MKCoordinateRegion(center: location.coordinate,
span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
hasSetRegion = true
}
}
}
}

struct ShowMapView: View {
@ObservedObject private var locationManager = LocationManager()

var homeLocation : [AnnotationItem] {
guard let location = locationManager.location?.coordinate else {
return []
}
return [.init(name: "Home", coordinate: location)]
}

var body: some View {
Map(coordinateRegion: $locationManager.region, annotationItems: homeLocation) {
MapPin(coordinate: $0.coordinate)
}
.frame(height: 300)
}
}

In this solution, the region is published by the location manager. As soon as a location is received, the region is centered on that spot (in didUpdateLocations). Then, a boolean flag is set saying the region has been centered initially. After that boolean is set, it no longer updates the region. This will let the user still drag/zoom, etc.

I also changed your code for putting down the pin a little bit. You were force-unwrapping location, which is nil until the first location is set by the location manager, causing a crash. In my edit, it just returns an empty array of annotation items if there isn't a location yet.

In widget using swiftui how to get current location?

class WidgetLocationManager: NSObject, CLLocationManagerDelegate {
var locationManager: CLLocationManager?
private var handler: ((CLLocation) -> Void)?

override init() {
super.init()
DispatchQueue.main.async {
self.locationManager = CLLocationManager()
self.locationManager!.delegate = self
if self.locationManager!.authorizationStatus == .notDetermined {
self.locationManager!.requestWhenInUseAuthorization()
}
}
}

func fetchLocation(handler: @escaping (CLLocation) -> Void) {
self.handler = handler
self.locationManager!.requestLocation()
}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.handler!(locations.last!)
}

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

call

var widgetLocationManager = WidgetLocationManager()

func getTimeline(for configuration: SelectPlaceIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
widgetLocationManager.fetchLocation(handler: { location in
print(location)
.......
})
}

How can I call an API with user's current location on app launch in SwiftUI?

As Joakim mentioned, you need to use .onAppear. This is due to the fact that you cannot access a property before it is set in a struct.

For your case, the code would look like this:

struct ContentView: View {

@StateObject var locationManager = LocationManager()

var userLocation: String {
let latitude = "\(locationManager.lastLocation?.coordinate.latitude ?? 0)"
let longitude = "\(locationManager.lastLocation?.coordinate.longitude ?? 0)"
return "\(latitude),\(longitude)"
}

@ObservedObject var api: randomAPI?

var body: some View {
SomeView()
.onAppear {
api = randomAPI(location: userLocation)
}
...

However, I don't think setting an ObservedObject right after the view appears is the best way to do this.

If I were you, I would remove the init method in the rapidAPI class:

class randomAPI: ObservableObject {
func callAPI(userLocation: String) {
...

And call the callAPI method when the view appears:

struct ContentView: View {

@StateObject var locationManager = LocationManager()

var userLocation: String {
let latitude = "\(locationManager.lastLocation?.coordinate.latitude ?? 0)"
let longitude = "\(locationManager.lastLocation?.coordinate.longitude ?? 0)"
return "\(latitude),\(longitude)"
}

@ObservedObject var api = randomAPI()

var body: some View {
SomeView()
.onAppear {
api.callAPI(location: userLocation)
}
...

Current Location is Nil In SwiftUI

I got the answer to my question and it is that you have to just add one line in case .authorizedAlways, .authorizedWhenInUse:

currentLocation = locManager.location

The whole code will:

        let locManager = CLLocationManager()
locManager.requestWhenInUseAuthorization()

var currentLocation: CLLocation?

switch locManager.authorizationStatus {

case .notDetermined, .restricted, .denied:
print("lat long will nil")

case .authorizedAlways, .authorizedWhenInUse:

currentLocation = locManager.location

let lati = currentLocation?.coordinate.latitude
let long = currentLocation?.coordinate.longitude

print("lat: \(lati) long: \(long)")

@unknown default:
print("error getting location")
}


Related Topics



Leave a reply



Submit