how to wait for requestLocation before proceeding? - swift

I'm requesting user location when a button is pressed which then triggers an API call. However I don't want to make this API call before the latitude/longitude values are obtained from the requestLocation() call. I thought I could just poll with a while loop checking if my optional variables latitude == nil || longitude == nil, but then just sits in the while loop forever. I need to have some kind of waiting for those values because if I don't it just would send nils to the API call, since it takes a few seconds to get the location. What would I do to make sure the API request isn't called until the latitude/longitude values are set from the requestLocation() call?

Call your api from this delegate method of CLLocationManagerDelegate
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
locationManager.stopUpdatingLocation()
let location = locations.last! as CLLocation
latittude = String(format: "%f", location.coordinate.latitude)
longitude = String(format: "%f", location.coordinate.longitude)
// call your api from here
}
HOPE THIS WILL HELP YOU.
THANKS

Make the api call in the delegate where the location is being updated. DidUpdateLocation. I don't remember the name exactly.
Didupdatelocations first location will be an older location so make sure the location you used to send the request is close to accurate.

Related

No stable location updates are received in CLLocationManager didUpdateLocations delegate. I don't know what is wrong

I am trying to get location updates with locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]). The locations are received. But when I am debugging the app in device, I have recorded some weird events.
One was that the phone was never removed from place while debugging but it recorded different locations over a period of 15 minutes and the distance summed up to around 50meters.
Another was that when the first time the delegate was fired, it provided the correct current location, but soon it moved some 800 meters away and then restored to correct location after some time.
What I am trying to do in this app is to calculate travelled distance over time. But since I am not getting correct data, the distance I am getting is wrong.
The locationmanager has been used in this way
locationManager = CLLocationManager()
locationManager.allowsBackgroundLocationUpdates = true
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.distanceFilter = 1
locationManager.activityType = .automotiveNavigation
locationManager.pausesLocationUpdatesAutomatically = true
and the lastLocation from delegate is saved and used
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let bestLocation = locations.last {
guard -(bestLocation.timestamp.timeIntervalSinceNow) < 5 || bestLocation.horizontalAccuracy > 0 else {
return
}
self.lastLocation = bestLocation
}
}
I am saving current location data and comparing it with the next one received every one second to calculate the distance.
So how do I fix this incorrect received location and calculate distance properly. My approach of doing this may be wrong, so please suggest me a better way of handling this.

Fetch Firebase/Geofire data only after getting user location

I'm developing a app that uses GeoFire to only get data from Firebase that are in 10km radius from the user location. And then populate a CollectionView.
The problem:
When internet is slow it loads the CollectionView with no data. Probably because the mobile didn't have time to get an accurate user location yet.
I have my fetchData() function inside ViewDidLoad().
How can I do to execute fetchData() function only after user location has been finished?
Desired flow:
- Launch App
- Get user location
- Populate the CollectionView with data only after getting user location
- Load CollectionView
Put your fetch data function outside ViewDidLoad
func fetchData(){
etc.
}
call it when location comes through in:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = manager.location else {return}
etc.
fetchData()
}

CLLocationManager is slow getting location, Swift

Im creating this app, and it needs to get the users location - its all working properly, the thing is, that the time from accepting the use of location services, to getting the actual location takes like 5 seconds - is this normal?
I've used other apps, where it goes much faster..
Here's what my code looks like:
override func viewDidLoad() {
super.viewDidLoad()
// Ask for Location-Authorisation from the User.
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.requestLocation()
}
mapView.delegate = self
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue: CLLocationCoordinate2D = manager.location!.coordinate
let initialLocation = CLLocation(latitude: locValue.latitude, longitude: locValue.longitude)
self.centerMapOnLocation(initialLocation)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("could not get location")
}
But the time from the application gets the location to put into the centerMapOnLocation-function, seems just to be quite long. What is to be expected, when getting a users location? I'm testing on a wifi connection, so I know its not because the internet is slow, or its a bad connection...
Anyone have an idea? :)
Best regards!
Try setting the accuracy and use locationManager.startUpdatingLocation(). I do that, and get answer within a second (on the device).
From the documentation of requestLocation():
This method returns immediately. Calling it causes the location manager to obtain a location fix (which may take several seconds) and call the delegate’s locationManager(_:didUpdateLocations:) method with the result.
Source
So basically, everything is fine with your code, it's just how the framework is built.
When initializing your location manager, add startUpdatingLocation():
let manager = CLLocationManager()
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.requestLocation()
manager.startUpdatingLocation()
Without startUpdatingLocation() geo-location takes about 5 seconds, with it, the request executes nearly immediately.
If you don't want to delay the app's launch for the location manager, consider deploying two location managers (in the app delegate), tasking one with generating a location quickly and the other with generating a location accurately:
fastLoc.delegate = self
fastLoc.desiredAccuracy = kCLLocationAccuracyThreeKilometers
fastLoc.requestWhenInUseAuthorization()
fastLoc.startUpdatingLocation()
bestLoc.delegate = self
bestLoc.desiredAccuracy = kCLLocationAccuracyBest
bestLoc.requestWhenInUseAuthorization()
bestLoc.requestLocation()
The combination of 3 km accuracy with startUpdatingLocation() should return a location almost instantly, almost always before the root view controller is even ready to go. bestLoc manager is likely to return a location well after the user has launched the app but it will be very accurate.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
switch manager {
case fastLoc:
fastLoc.stopUpdatingLocation()
deviceLocation = locations.last! // set property with fast loc
case bestLoc:
deviceLocation = locations.last! // overwrite property with best loc
default:
break
}
}

Trouble getting one-time user location in Swift

I am trying to get the user's location at the time of a button press, however I am having trouble setting up the location code. I've been looking between various answers on Stackoverflow but I can't get anything to work for me.
class MyViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedAlways || status == .AuthorizedWhenInUse {
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
print("coordinates:")
print(latitude)
print(longitude)
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locationValue : CLLocationCoordinate2D = manager.location!.coordinate
print("locations = \(locationValue.latitude) \(locationValue.longitude)")
}
However I just get nils from the prints in didChangeAuthorizationStatus and nothing ever prints from didUpdateLocations. Im also really confused about where to put startUpdatingLocation(). Some answers place it directly in viewDidLoad as I have here, others place it in didChangeAuthorizationStatus, and I saw another place it inside an if CLLocationManager.locationServicesEnabled() in didLoad. What is the correct way to do this? And also what have I done wrong that I'm not getting any values printing? I'm running on the emulator, have location turned on and allowed permissions in the pop-up, and have the emulator set to a lat/long custom location, and I have added the values in pList.
edit: even tried copy/pasting the code from this to get user's location only once but it returns (kCLErrorDomain error 0.). I added a 'requestWhenInUseAuthorization()` to their code but it still fails.
get nils from the prints in didChangeAuthorizationStatus
Because we don't have any locations yet. That's the wrong place to ask for that information. All that happened is that we are now authorized.
nothing ever prints from didUpdateLocations
Because you're running on the simulator, perhaps. Try running on a device.
And, if your goal is just to get the location and stop, don't use startUpdatingLocation; call requestLocation. That's what it's for.

requestLocation() in iOS 9 calls the didUpdateLocation delegate multiple times

So there is the new requestLocation() method on iOS9. I am trying to use it to get only one location update but it hits the didUpdateLocations multiple times.
Isn't this suppose to call it only once ? i have set distanceFilter to 1000.0, so it is pretty broad to help return quickly. Any ideas ?
even if i call the stopUpdatingLocation() inside the delegate method, i still get three hits of the delegate.
Note: same behavior occurs when i use StartUpdatingLocation instead, i want only a single return as i want to obtain the user's current country, so feed the location to reversegeocoder
thanks in advance
Here is the code:
func getLocationOneTime(accuracy: Double){
print("Acquiring location one time - accuracy requested:\(accuracy)")
locationManager.distanceFilter = accuracy
locationManager.desiredAccuracy = accuracy
// Start gpsOneTimeTimeout timer
gpsTimeoutTimer = NSTimer.scheduledTimerWithTimeInterval(gpsOneTimeTimeout, target: self, selector: #selector(self.reportTimeout), userInfo: nil, repeats: false)
locationManager.requestLocation()
}
Usually for this kind of problem I just use an if statement to prevent the delegate function changing anything after the first call
in this case if you are just looking for the location I would do:
let locationManager = CLLocationManager()
var userLocation: CLLocation!
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if userLocation == nil {
if let location = locations.first {
userLocation = location
self.locationManager.stopUpdatingLocation()
}
}
}
Edit: I had a look at the apple documentation for this and you are doing things right, I doubt you'll be able to prevent it through any reasonable means sadly.