RequestLocation taking too long - ios

I am using location.requestLocation in swift 5 for my ios app. But its taking way too long time. around 10 seconds. searching for solutions online, they are saying use startUpdatingLocation instead..but problem is I only want it once... not continuous update. I am also not interested in it being accurate.I can have it wrong by some margin.
Because all I want is just zoom to my google map position, and sort stuff by distance using user location. Location can be wrong up to 3 - 4 Kilometers I have no problem.
override func viewDidLoad() {
super.viewDidLoad()
//mapView.showsUserLocation = false
locationManager.delegate = self
print(locationManager.distanceFilter)
switch CLLocationManager.authorizationStatus() {
case CLAuthorizationStatus.notDetermined, .restricted, .denied:
locationManager.requestWhenInUseAuthorization()
case CLAuthorizationStatus.authorizedWhenInUse, .authorizedAlways:
requestLocation()
#unknown default: break
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print("\nStart of locationManager(didChangeAuthorization)")
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == CLAuthorizationStatus.authorizedWhenInUse
|| authStatus == CLAuthorizationStatus.authorizedAlways {
requestLocation()
}
print("\nEnd of locationManager(didChangeAuthorization)")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("\nStart of locationManager(didUpdateLocations)")
zoomInLocation(locations.last!)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
if let err = error as? CLError, err.code == .denied {
manager.stopUpdatingLocation()
return
}
print("\nlocationManager(): \(error.localizedDescription)")
}
private func requestLocation() {
print("\requestLocation() called")
// check if the location service is availalbe on that device
if !CLLocationManager.locationServicesEnabled() {
return
}
locationManager.requestLocation()
}
private func zoomInLocation(_ location: CLLocation) {
loca2 = location
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: 6.0)
(view1 as! GMSMapView).animate(to: camera)
print("\nzoomInUserLocation(): mapView[latitude]=\(location.coordinate.latitude), locationManager[latitude]=\(String(describing: location.coordinate.latitude))")
let coordinateSpan = MKCoordinateSpan(latitudeDelta: 20, longitudeDelta: 20)
_ = MKCoordinateRegion(center: location.coordinate, span: coordinateSpan)
// mapView.centerCoordinate = location.coordinate
//mapView.setRegion(coordinateRegion, animated: true)
if(i1 != 0){
self.sortByDistance()
}
}

Related

swift user location - update if move

So I have been able to get the users location via the following code.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status != .authorizedWhenInUse {return}
print("test LOCATION BELOW")
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
let locValue: CLLocationCoordinate2D = manager.location!.coordinate
print("UUID: \(String(describing: uuid)) locations = \(locValue.latitude) \(locValue.longitude)")
}
However I want to watch the users location and if they move update their location.
I am wondering how do I get this code to keep checking for the users location?
My
override func viewDidLoad(){
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.requestAlwaysAuthorization()}
I get it popping up the request and I approve it but it does not run the code
Here is how you can get the location data. The code is similar to yours but with a bit of change and additions.
First check if you already have user's permission to get their location data.
func isLocationServicesEnabled() -> Bool {
if CLLocationManager.locationServicesEnabled() {
switch(CLLocationManager.authorizationStatus()) {
case .notDetermined, .restricted, .denied:
return false
case .authorizedAlways, .authorizedWhenInUse:
return true
#unknown default:
return false
}
}
return false
}
If this method returns false you can ask for authorization.
// Initialize manager in your viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.delegate = self
// Do other stuff
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Check for auth
if isLocationServicesEnabled() {
locationManager.startUpdatingLocation()
} else {
locationManager.requestWhenInUseAuthorization()
}
// Do other stuff
}
Finally in your CLLocationManagerDelegate implementation get the coordinates.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last?.coordinate else { return }
// Use location.latitude and location.longitude here
// If you don't want to receive any more location data then call
locationManager.stopUpdatingLocation()
}
First, you have to check that you have user's permission to get their location data
func checkLocationServicesAuthorization() -> Bool {
if CLLocationManager.locationServicesEnabled() {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
return false
case .restricted, .denied:
//code for open settings screen in user’s phone
return false
case .authorizedWhenInUse, .authorizedAlways:
return true
default:
return false
}
} else {
//code for open settings screen in user’s phone
}
return false
}
And
override func viewDidLoad() {
super.viewDidLoad()
locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.delegate = self
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if checkLocationServicesAuthorization() {
locationManager.startUpdatingLocation()
} else {
locationManager.requestWhenInUseAuthorization()
}
}
You can use delegate method didUpdateLocations of CLLocationManagerDelegate and don't forgot to connect delegate yourLocationManager.delegate = self
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0] as CLLocation
// Call stopUpdatingLocation() to stop listening for location updates, other wise this function will be called every time when user location changes.
// yourLocationManager.stopUpdatingLocation()
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else { return }
let latitude = String.init(userLocation.coordinate.latitude)
let longitude = String.init(userLocation.coordinate.longitude)
print("\(latitude), \(longitude)")
}

Swift - GMSMapView animate(toLocation:) / animate(to:CameraPositon) not working

This is how I init the map - GMSMapView
class ViewController: UIViewController {
var map = GMSMapView()
override func viewDidLoad() {
super.viewDidLoad()
setupGoogleView()
}
private func setupGoogleView() {
guard let coordinates = getUserLocation() else { return }
let camera = GMSCameraPosition.camera(withLatitude: coordinates.latitude, longitude: coordinates.longitude, zoom: 16.0)
self.map = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
map.settings.tiltGestures = false
map.mapType = .satellite
map.delegate = self
map.frame = view.frame
self.view.addSubview(map)
}
}
The problem comes when I call this function from somewhere else in the file
private func animateTo(location: CLLocationCoordinate2D) {
DispatchQueue.main.async {
let cameraPosition = GMSCameraPosition(target: location, zoom: 20)
self.map.animate(toLocation: location)
self.map.animate(to: cameraPosition)
}
}
I am trying to relocate the camera to some coordinates, but nothing happens.
I have tried every solution on stackoverflow and google.
I have lat and lng in the location - checked. The function is called - checked.
I have also tried to self.view.layoutSubviews(), self.view.layoutIfNeeded(), and also for map
try to use CLLocationManagerDelegate
// Handle authorization for the location manager.
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .restricted:
print("Location access was restricted.")
case .denied:
print("User denied access to location.")
// Display the map using the default location.
mapView.isHidden = false
case .notDetermined:
print("Location status not determined.")
case .authorizedAlways: fallthrough
case .authorizedWhenInUse:
print("Location status is OK.")
getFilialList()
#unknown default:
fatalError()
}
}
then
// Handle incoming location events.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location: CLLocation = locations.last!
print("Location: \(location)")
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
zoom: 12)
DispatchQueue.main.async {
self.mapView.animate(to: camera)
self.locationManager.stopUpdatingLocation()
}
}
I manage to solve the issue with this:
self.view.subviews.forEach { (view) in
if let mapView = view as? GMSMapView {
// do update on mapView here
}
}

How to access user location manually if the user denies location permission in iOS swift

I want to access the user location of the user even if the user has denied the permission .how to get the user location if its manually.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
determineMyCurrentLocation()
}
func determineMyCurrentLocation() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
mapView.showsUserLocation = true
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse || status == .authorizedAlways {
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0] as CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.20, longitudeDelta: 0.20))
print("user latitude = \(userLocation.coordinate.latitude)")
print("user longitude = \(userLocation.coordinate.longitude)")
self.mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("error::: \(error)")
}

Add the camera on current position of the user on the map

I added this code in my viewController
import UIKit
import CoreLocation
import GoogleMaps
class CourseClass2: UIViewController, UITableViewDelegate, UITableViewDataSource, UINavigationControllerDelegate {
#IBOutlet weak var mapView: GMSMapView!
}
and this extension
extension CourseClass2: CLLocationManagerDelegate {
func determineMyCurrentLocation() {
guard currentLocation == nil else {
return
}
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
locationManager?.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0] as CLLocation
manager.stopUpdatingLocation()
print("user latitude = \(userLocation.coordinate.latitude)")
print("user longitude = \(userLocation.coordinate.longitude)")
didReceiveUserLocation(userLocation)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error \(error)")
errorGettingCurrentLocation(error.localizedDescription)
}
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse || status == .authorizedAlways {
locationManager?.startUpdatingLocation()
//locationManager.startUpdatingHeading()
} else if status == .denied || status == .restricted {
errorGettingCurrentLocation("Location access denied")
}
}
func errorGettingCurrentLocation(_ errorMessage:String) {
let alert = UIAlertController.init(title: "Error", message: errorMessage, preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
}
to get the user location. Now i would like to add in the viewDidLoad of my controller a camera like let camera = GMSCameraPosition.camera(withLatitude: , longitude: , zoom: 14) on the user position, but how can i do to use in this line the latitude and longitude of my user current position that i found with my extension?
You need to call locationManager.startUpdatingLocation() in viewDidLoad() where locationManager is CLLocationManager object. As soon as your current location is retrieved, didUpdateLocations delegate method is called where you can set the camera position as follows:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation = locations.last
let location = GMSCameraPosition.camera(withLatitude: userLocation!.coordinate.latitude, longitude: userLocation!.coordinate.longitude, zoom: 16.0)
mapView.animate(to: location)
}

MapView doesn't ask for location permission

I'm trying to build a mapView in Swift. It already worked but after I changed something I can't remember, I'm now getting the following error:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
The NSLocationAlwaysUsageDescription is in my .plist file.
Here is the code:
import UIKit
import MapKit
class AwesomeMap : UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
var map: MKMapView?
var manager: CLLocationManager?
func setup() {
manager = CLLocationManager()
manager!.delegate = self
map!.delegate = self // map is being set from another controller
manager!.requestAlwaysAuthorization()
manager!.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
println("permisison did change")
if(status == CLAuthorizationStatus.AuthorizedWhenInUse || status == CLAuthorizationStatus.Authorized) {
map!.showsUserLocation = true
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
for location in (locations as Array) {
var loc = (location as CLLocation)
println(loc.coordinate.latitude)
let region = MKCoordinateRegion(center: loc.coordinate, span: MKCoordinateSpanMake(0.05, 0.05))
map!.setRegion(region, animated: true)
}
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("fail")
}
}
Old code before implementing a few suggestions:
import UIKit
import MapKit
class AwesomeMap : UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
var manager = CLLocationManager()
var map: MKMapView?
func setup(mapView: MKMapView) { // passing the IBOutlet from another controller
// the change I made was around the following six lines I think...
map = mapView
map!.delegate = self
manager.delegate = self
manager.requestAlwaysAuthorization()
map!.showsUserLocation = true
manager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
for location in (locations as Array) {
var loc = (location as CLLocation)
println(loc.coordinate.latitude)
let region = MKCoordinateRegion(center: loc.coordinate, span: MKCoordinateSpanMake(0.05, 0.05))
map!.setRegion(region, animated: true)
}
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("fail") // nothing happens here
}
}
You're only allowed to call
map!.showsUserLocation = true
after your Location Manager has got the Permission to use the user Location.
Like in (got no swift version of this, but you'll probably get the point)
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if(status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways)
{
self.mapView.showsUserLocation = YES;
}
}
Go to Simulator settings
after that enter Location Services and turn on . if you need location blue dote in MapView enter <> and set << While Using the App >>
Do not call showsUserLocation when authorization status is undetermined.
func setup(mapView: MKMapView) { // passing the IBOutlet from another controller
map = mapView
map!.delegate = self
manager.delegate = self
manager.requestAlwaysAuthorization() // Does not if status is determined.
self.locationManager(manager: manager, status: CLLocationManager.authorizationStatus())
}
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .Authorized {
map!.showsUserLocation = true
manager.startUpdatingLocation()
}
}
I have this working code in my app (reduced):
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.Authorized {
manager.startUpdatingLocation()
}
additionaly, you can react on any user's authorization status changes:
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .Authorized {
manager.startUpdatingLocation()
}
}

Resources