I'm doing a query inside of:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
if (!gotLocation){
gotLocation = true;
[locationManager stopUpdatingLocation];
// DO QUERY
}
}
But I would like to know when the final location is set, or when a more accurate one is made. I'm trying to query only once and need a precise location for the query. I know I can use [locations lastObject], but how can I determine when the final or a more precise location is set.
You can check the location's horizontalAccuracy. The smaller the value the more accurate. You should hold a reference to the last location you received then when a new location comes in that is more accurate, the horizontalAccuracy is smaller, updated your reference.
Then once you receive a location with a horizontalAccuracy close enough for your use case then you can call stopUpdatingLocation since you have your location, then do your query.
For example:
CLLocation *location = [locations lastObject];
if (location.horizontalAccuracy < self.lastLocation.horizontalAccuracy) {
self.lastLocation = location;
if (self.lastLocation.horizontalAccuracy <= kDesiredLocationAccuracy) {
// execute query or additional logic
[locationManager stopUpdatingLocation];
}
}
Hope that helps!
Related
IOS10 on iPhone 6 Plus.
A small app app that grabs the gps coordinates and sends them to a remote web service. On the iphone map the user location is showing correctly, but the retrieved coordinates:
location.coordinate.latitude,
location.coordinate.longitude
are 0.5 miles away from where the map says I am! This is consistent wherever I move to.
I am following Apple's best practices and using the delegate method as follows: and it's these coordinates that are incorrect.
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0) {
// Log the data
NSLog(#"latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude);
}
}
I am setting the location accuracy as follows:
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
I sample the gps coordinates for 30 seconds to make sure i am getting the best accuracy possible.
I have tried this on 2 different iPhones, both showing the same issue.
Thanks in advance.
I finally found out what is causing the problem..
I am currently in China... and that is the reason for the mysterious offset.. the maps in China are 'offset'.
If you are interested there's an post about it here that has saved me from tearing my hair out.
http://www.sinosplice.com/life/archives/2013/07/16/a-more-complete-ios-solution-to-the-china-gps-offset-problem.
China uses a mapping projection called GCJ-02 which is different from the West's mapping standard (WGS-84). So if you're ever developing a mapping system, you might want to take this into account for travellers in China!
Thanks anyway for the useful pieces of coding advice.
You can add a check in your method to update locations again until you are down to your desired accuracy:
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
// You can check for either locationManager.desiredAccuracy or a value you'd like in meters
CLLocation* location = [locations lastObject];
if (location.horizontalAccuracy > locationManager.desiredAccuracy) {
//Do nothing yet
return;
}
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0) {
// Log the data
NSLog(#"latitude %+.6f, longitude %+.6f\n",
location.coordinate.latitude,
location.coordinate.longitude);
}
}
I'm using Parse and with geoPointForCurrentLocationInBackground I can stop updating once a location is received without having to manually stop it.
How do I stop updating location immediately right after I receive location using CLLocationManager?
Edit
I know [self.locationManager stopUpdatingLocation]; stops it.
What I'm really asking is, how do I know I've received location for the first time then stop it immediately?
After getting your location, use this method:
[self.locationManager stopUpdatingLocation];
self.locationManager = nil;
Call stopUpdatingLocation as soon as your didUpdateLocations method is called.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
[manager stopUpdatingLocation];
//store your location
self.location = [locations lastObject];
}
BOOL first_time = YES; // public
Every time you start updating location set first_time to YES:
first_time = YES;
[self.locationManager startUpdatingLocation];
in your didUpdateUserLocation method:
if (userLocation == nil) {
NSLog(#"User location is nil. maybe wating for permission");
} else if (!CLLocationCoordinate2DIsValid(userLocation.coordinate)) {
NSLog(#"User location is not valid 2d coordinates. maybe called in background");
} else {
NSLog(#"Did update user location: %f %f", userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude);
// here is the first time you receive user location
if (first_time)
{
first_time = NO;
[self.locationManager stopUpdatingLocation];
}
}
call below method to save and stop location after you get it once
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
self.location = [locations lastObject]
self.locationManager.delegate = nil;
[self.locationManager stopUpdatingLocation];
}
The opposite of stopMonitoringSignificantLocationChanges is not stopUpdatingLocation, it is startMonitoringSignificantLocationChanges.
Check out the CLLocation documentation for further detail.
Finally found the answer in another question...reprinting it here because it took me a while to stumble on it.
I had to call this:
[_locationManager stopMonitoringSignificantLocationChanges];
Even though I never called startMonitoringSignificantLocationChanges in the first place, seems I had to "un-call" it...strange that it works this way, but as soon as I added that line, location services shut down promptly. Hope this helps someone else.
Once current location update stop location manager using stopUpdatingLocation.
region.center = self.mapView.userLocation.coordinate;
if (region.center.longitude != 0 && region.center.latitude != 0) {
[self.locationManager stopUpdatingLocation];
}
self.yourLocationManager.stopUpdatingLocation()
I am having an issue with sending location to other users. I using Parse.com as my backend and I use this code to get a location:
-(void)sendLocation{
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]){
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[locationManager stopUpdatingLocation]; //kill it NOW or we have duplicates
if(!self.haveLocation) {
self.haveLocation=YES;
NSLog(#"didUpdateToLocation: %#", newLocation);
self.currentLocation = newLocation;
self.currentLocationGeoPoint= [PFGeoPoint geoPointWithLocation:self.currentLocation];
}
If I send myself a message from my current location and then open the message to view it, by comparing the current location circle with the pin dropped I can see they aren't in the same place and a fair distance apart.
I have the BOOL var haveLocation to make sure it is only refreshed once. Do I need to refresh it more times or something? Any pointers on how to make this more accurate would be really appreciated! Thanks
I tried following the apple example LocateMe:
I now have:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
// test that the horizontal accuracy does not indicate an invalid measurement
if (newLocation.horizontalAccuracy < 0) return;
// test the measurement to see if it is more accurate than the previous measurement
if (self.bestEffortAtLocation == nil || self.bestEffortAtLocation.horizontalAccuracy > newLocation.horizontalAccuracy) {
// store the location as the "best effort"
self.bestEffortAtLocation = newLocation;
if (newLocation.horizontalAccuracy <= locationManager.desiredAccuracy) {
[locationManager stopUpdatingLocation];
//this code after getting the location
NSLog(#"didUpdateToLocation: %#", newLocation);
}
}
}
However when I tap send location it just runs forever and doesn't stop updating.. I have locationManager.desiredAccuracy = kCLLocationAccuracyBest; set too.
The location manager may send you several updates as it improves its accuracy. This is a feature designed to give you information it as as quickly as possible, while eventually getting the best information to you (at least up to the accuracy you requested). You are actively avoiding those updates, so you are likely getting the least accurate information.
You should check the horizontalAccuracy to determine if it is accurate enough for your use.
Note that you cannot compare horizontalAccuracy to kCLLocationAccuracyBest. "Best" is a constant -1. You need to compare it to what you need (in meters), and probably set a timeout to give up if it takes too long to get there (the system may not be able to provide you an arbitrarily accurate value.)
I wrote a simple iOS application that retrieves location information and then uses the location to request Yahoo Weather.
The problem is that even when I call the Core Location in the viewDidLoad, it won't give me the result immediately.
So why can't I get the location information?
How can I get the location information in viewDidLoad?
The pseudocode currently is something like:
- (void)viewDidLoad
{
[super viewDidLoad];
self.locManager = [[CLLocationManager alloc] init];
self.locManager.delegate = self;
self.locManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locManager.distanceFilter = 100;
[self.locManager startUpdatingLocation];
//won't get the current location right now, so the output will be null
NSLog(#"Current Location Longitude: %#", self.longitudeString);
NSLog(#"Current Location Latitude: %#", self.latitudeString);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
self.longitudeString = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
self.latitudeString = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
Location updates are not provided as instantly as you are expecting, you need to wait few seconds (2-3 or may be more) to get precise location update. If you want to have location data in viewDidLoad then you should init your location manager (and call startUpdatingLocation) before invoking the ViewController (since then it is not guaranteed that you will have location-data in viewDidLoad).
I want the current latitude and longitude of my device. I can print latitude and longitude when my program locate the device for the first time but I can't refresh it.
-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
int lastindex = [locations count]-1;
CLLocation * currentLocation = [locations objectAtIndex:lastindex];
float latitude =currentLocation.coordinate.latitude;
float longitude =currentLocation.coordinate.longitude;
NSLog(#"LAT:%f LONG:%f",latitude,longitude);
[self latitudeLabel].text = [[NSString alloc]initWithFormat:#"latitude : %#",[[NSNumber numberWithFloat:latitude] stringValue]];
[self longitudeLabel].text = [[NSString alloc]initWithFormat:#"longitude : %#",[[NSNumber numberWithFloat:longitude] stringValue]];
}
This is what I tried but latitude/longitude are never updated. I tried it with the function didUpdateHeading but that didn't work either.
How can i do this. Any one can help me to solve this issue.
Thanks you
This method is triggered by startUpdatingLocation which I assume you're using since it did get called at least once. The method gets called each time the location data changes. Is your location actually changing enough to trigger it? Also, check the distanceFilter property on your CLLocationManager and make sure it is low enough.
Make sure you add the following to your header:
#interface YourLocationObject : SomeObject <CLLocationManagerDelegate>
.. and when you create your CLLocationManager object, you set yourself as the delegate:
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//... other customization here ...//
[locationManager startUpdatingLocations];