Always negative speed iOS - ios

I'm using the delegate method:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
To get the current and old location, I used:
CLLocation *newLocation = [locations lastObject];
self.currentUserLocation = newLocation;
if(self.oldLocation == nil)
{
self.oldLocation = newLocation;
return;
}
EDIT 1: I can get the old location now.
But I always have a negative speed when I use [newLocation speed]; = -1
The device used is an iPhone 4s. Do you have an idea ?
Also, for the locationManager, I used kCLLocationAccuracyBestForNavigation and kCLDistanceFilterNone. I can see on the map my current location moving.
EDIT 2:
I finally achieve the issue with the speed using this method:
- (CLLocationSpeed)speedTravelledFromLocation:(CLLocation*)fromLocation;
{
NSTimeInterval tInterval = [self.timestamp timeIntervalSinceDate:fromLocation.timestamp];
double distance = [self distanceFromLocation:fromLocation];
double speed = (distance / tInterval);
return speed;
}
This method returns the speed calculated from the distance and time deltas between self and fromLocation.
I found this method in this repository: https://github.com/100grams/CoreLocationUtils
Hope it will help someone ;)
EDIT 3
Got it! It was because I'm testing on simulator! I tested on a device and the speed using [newLocation speed] is correct!
Thank you for your help.
Regards,
Lapinou.

Negative speed usually means you don't have a GPS signal.

Why are you expecting the location callback to have 2 or more locations?
This method:
(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
Usually delivers you just one location, except if for some reason multiple locations arrived before that method was called, but you usually will get just one location.
The problem is that you are assuming that that method gives you your previous location along with the new one, and it's not like that.

Related

iOS location manager update more often then once in a second

I created location manager with
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
but location updates received once per second.
Is it possible to get updates more often?
I tried to get current location in timer, but it's still updated once per second.
Here's what I did:
[self pingLocation];//viewDidLoad
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
[manager stopUpdatingLocation];
manager.delegate = nil;
self.currentLocation = (CLLocation *)[locations lastObject];
}
- (void) pingLocation {
[locationManager startUpdatingLocation];
locationManager.delegate = self;
[self performSelector:#selector(pingLocation) withObject:nil afterDelay:0.5];//change to whatever you want
}
This seemed to give me fairly good results and could make it update more than once per second. However, it drains battery very drastically and is not the best practice. I would ask yourself: why do you want this? Do you really need more than one update per second?
Edit: I've just tested this again and I believe that although it appears to update every half second, it doesn't really. For example:
30.00000, 60.00000
30.00000, 60.00000
30.00032, 60.00056
30.00032, 60.00056
Thus, you really can't update faster than a second, sorry to say.
According to the CLLocation.startUpdatingLocation documentation:
Calling this method several times in succession does not automatically
result in new events being generated. Calling stopUpdatingLocation in
between, however, does cause a new initial event to be sent the next
time you call this method.
You will probably have to also set distanceFilter to none. However, you can imagine these two will help churn through a battery.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
[locationManager startUpdatingLocation];
}
By this, location manage get update more often. Because every time when it get update it will request for another location frequently.

locationManager: didEnterRegion: triggered without location change

I have an app that monitors some regions (geofencing) that each region represent a store, the app notifies the user whenever he approaches to a store.
For some reason, the app sends a notification every around 20 minutes when the user is already inside the region's circle.
It's all working fine, but when the user is inside a region for a long time the app will keep notifying him until he'll exit the region.
Any idea why is it happening? Thank you!
When you create a locationManager and call startUpdatingLocation, it starts giving you co-ordinates of your simulator or device continuously, with a very slight differences in the co-ordinate's values. You need to call stopUpdatingLocation.
For your case you need to stopUpdatingLocation when user exist the region or you can record the last location like this:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
[locationManager stopUpdatingLocation];
}
We have the same thing happening. We just keep track of the region coordinate and when the new one comes in we have a method to determine if the new coordinate is 'significantly different' from the region we are in. If it is not, then we ignore it. If it is, then we take our next appropriate action. I hope that helps!
* UPDATE *
Here is how we determine that there was enough change to take action:
- (BOOL) radiiAreSignificantlyDifferent:(CLLocationDistance) newRadius oldRadius:(CLLocationDistance)oldRadius
{
// radii are in kilometers
return (newRadius > oldRadius + 1.5 || newRadius < oldRadius - 1.5) ? YES : NO;
}
- (BOOL) locationsAreSignificantlyDifferent:(CLLocation*) newLocation oldLocation:(CLLocation*)oldLocation
{
BOOL different = NO;
if (oldLocation == nil) {
different = YES;
}else{
// have we moved at least a quarter mile?
different = ([newLocation distanceFromLocation:oldLocation] > 400.0)? YES : NO;
}
return different;
}

CLLocation not giving actual speed

Here is my location manager delegate code.
It is not giving speed when we move using car so at least speed value should change.
It always gives constant value -1.00.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *crnLoc = [locations lastObject];
self.speedometerCurrentValue=crnLoc.speed;
self.lblSpeed.text=[NSString stringWithFormat:#"%f",crnLoc.speed];
}
Please check this screenshot from apple explanations. Your speed is invalid.

Show an alert when lon/lat is near

I have an application working on iOS devices getting constantly the current latitude and longitude from the device. I would like to show an alert when the user reaches a certain lon/lat.
Here is the long to be reached : 2.39364456
Here is the lat to be reached : 48.84185814
When the user reaches this point, he should get an alert.
Unfortunately it doesn't work since the user doesn't always get to this exact point.
What I would like to do is : if you are NEAR to this point, in a certain range defined, then we pop up the alert.
I have no idea how to do this. I tried to implement long/lat to UTM converter and then try to work with UTM format but it was a failure.
Is it possible to work with the lon/lat's numbers which are after the comas to make a "range" to be in so the pop up shows ?
Thanks for reading and thanks in advance for your help ;)
Sounds like you are looking for the region monitoring functionality that comes in Core Location in iOS.
Here is a related question that talks about that.
And here is some Apple sample code.
And the latest Apple documentation that talks about Region Monitoring.
When your app gets into the region you're watching, your app gets called with the CLLocationManager delegate "locationManager:didEnterRegion:" method. And that is where you can fire your UIAlert from.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
CLLocation *locA = [[CLLocation alloc] initWithLatitude:currentLocation.coordinate.latitude longitude:currentLocation.coordinate.longitude];
}
CLLocation *locB = [[CLLocation alloc] initWithLatitude:lat2 longitude:long2];
distance = [locA distanceFromLocation:locB];
if(distance<yourDesiredDiustance)
{
show Alert
}
}
You have 2 locations, aCLLocationA which is position defined by you, and aCLLocationB user location which get's updated. Now what you do:
Step 1
Find the distance by using this code between points on Map:
CLLocationDistance distance = [aCLLocationA distanceFromLocation:aCLLocationB];
Step 2
if(distance<=yourRange)
{
//You have to show popup, because your location is in range with that point
}

Ensure locationManager has finished then perform request

I am using CoreLocation to grab the users location. I need to grab the users location then send that to the server. I have it all working, but! I am implementing locationManager:(CCLLocationManager *)manager...
My url request is hitting before the location is found. Whats the best way to:
Request location
Store in string
Send string to request
I want to ensure the location is found before its sent. Do I check against the instance of the class with a conditional and inside the block hit the server. I dont need to keep updating, just grab once and stopUpdatingLocation
Was going through this post previously: Getting Longitude/Latitude of the User When the viewDidLoad
What I have so far:
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[locationManager startUpdatingLocation];
...more below... server request below here
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSLog(#"found!");
[locationManager stopUpdatingLocation];
}
}
Thoughts on how to do that? I think the conditional may work, but not sure if there was a proper way to handle that using the methods provided from CoreLocation.
Create a new method that will perform your location-dependent code. Then once you have the location (I.e. After the NSLog(#"found!"); line), call this method.
Note that the method may get called multiple times as the location accuracy improves - you might want to handle this.
For example:
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil)
{
NSLog(#"found!");
[self handleLocation:newLocation];
[locationManager stopUpdatingLocation];
}
}
- (void)handleLocation:(CLLocation*)location
{
// handling code here
}
The location manager is asynchronous. You have to ask for location updates, then wait for it to call you back.
Worse, the first several updates are usually garbage that needs to be thrown away.
The first location update frequently has a timestamp that is hours, days, or even weeks old. You first have to check to make sure the timestamp is in the last few seconds.
Once you've done that, you need to check the horizontal accuracy, and make sure the reading is accurate enough. Often when you first start the location manager the first few readings have an accuracy value of more than a kilometer, which is awful. (Accuracy is really a radius value. You can only be sure that the location you get is somewhere inside a circle with the specified radius.) You need to come up with an app-specific accuracy reading that is "good enough", and throw away accuracy readings until you get one that is good enough. You also need to check for negative accuracy readings, which mean that the GPS is returning invalid values.
Next, you have to allow for the case where the GPS doesn't settle down in a reasonable time. (Sometimes it can take multiple minutes, or simply fail to get a good reading.) In that case you need to handle it as a failure.
So, to handle all that you need to write your locationManager:didUpdateLocation: method to check the time stamp and the horizontal accuracy to make sure the reading is actually good. You also need to make sure you time out and report a failure if you can't get a decent location reading after a reasonable wait. One way to do this is to start a "give up" timer when you first begin location updates, and after you get a good reading, kill it. If the timer fires, stop location updates and report a "can't get a good location reading" error to your user. Understand that it's not uncommon to take 10 or 15 seconds to get a decent accuracy reading.

Resources