I have an application where I have to check that whether user's mobile location has changed or for 30 consecutive seconds or not?If it has not changed in 30 seconds then user will be navigated to the other view and if it has changed then user will have a message that your mobile location's coordinates have changed in these 30 seconds.
I am using these code but it does nothing ...
-(void)time
{
for(int i = 0; i<= timeremaining ;i++)
{
if (new1 == old)
{
if(timeremaining == 1)
{
Timer90 *timerview = [[Timer90 alloc] initWithNibName:#"Timer90" bundle:nil];
[self.navigationController pushViewController:timerview animated:YES];
}
}
else
{
[NSTimer cancelPreviousPerformRequestsWithTarget:self selector:#selector(time) object:nil];
}
timeleft.text = [NSString stringWithFormat:#"%d",timeremaining];
}
timeremaining--;
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
new1 = newLocation;
old=oldLocation;
latitude = [[NSString alloc]initWithFormat:#"%g",newLocation.coordinate.latitude];
longitude = [[NSString alloc]initWithFormat:#"%g",newLocation.coordinate.longitude];
accuracy = [[NSString alloc] initWithFormat:#"%g",newLocation.horizontalAccuracy];
if(oldLocation == NULL)
{
oldLocation == newLocation;
}
}
here timer90 is name of my view.Please help me out friends...Any help will be appreciated.
You could possibly do something like this (after adding counter and initialLocation to your properties) it will compare location after 30 seconds following the first update, but I think it would be helpful if you added an age check to the entire method so that you aren't comparing to some very old data point.
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if(self.counter==0){
self.intialLocation=newLocation;
self.counter=1;
}
NSTimeInterval age = [initialLocation.timestamp timeIntervalSinceNow];
if(age>30)
{
self.counter=0;
if(newLocation.latitude==initialLocation.latitude&&newLocation.longitude==initialLocation.longitude){
Timer90 *timerview = [[Timer90 alloc] initWithNibName:#"Timer90" bundle:nil];
[self.navigationController pushViewController:timerview animated:YES];
}
}
}
Two things that I notice. May be the whole issue, or only part of it.
Number 1.
if(oldLocation == NULL)
{
oldLocation == newLocation;
}
oldLocation == newLocation will not set the two equal to each other (you need one equals sign) and your are assigning the parameter pointers to the same object, not your member pointers. For example, if oldLocation points to Object A and newLocation points to Object B at the start of didUpdateToLocation:fromLocation:, then:
new1 is set to point at Object B
old is set to point at Object A
if(Object A is NULL)
oldLocation and newLocation both point at Object B
The values of new1 and old are not set to the same object in the NULL case. Which is what you are checking for in time
Number 2.
In time you are checking if new1 and old are pointing at the same object. No necessarily if the two objects represent the same location. In the case where oldLocation is null and they are set together, this check may pass...however, it is more likely that CoreLocation will call the update method a few times while accuracy gets better, and you will have two separate objects that represent the same lat/long location.
You should compare these two locations for proximity using the CLLocation getDistanceFromLocation: method.
Hope that Helps!
Related
I want to move added annotation to newlocation, below is the code and in else part i want to do that :
In previous code, new annotation is added and previous annotation is removed, but its get affected in degree of direction. So, i want to move annotation with out adding new annotation.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (newLocation.horizontalAccuracy < 0)
return;
if (!newLocation)
return;
static BOOL annotationAdded = NO;
self.currentLocation = newLocation;
self.previousLocation = oldLocation;
if(self.currentLocation != nil)
{
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(self.currentLocation.coordinate.latitude, self.currentLocation.coordinate.longitude);
myAnnotation = [[MyAnnotation alloc] initWithCoordinates:location title:#"Current Location" subTitle:nil];
if (!annotationAdded)
{
annotationAdded = YES;
[self.myMapView addAnnotation:myAnnotation];
}
else
{
// Here i want to move added annotation to newlocation coordinates
}
}
}
The way it works, is that you feed the map with annotations and then it fires the function that plot the annotations on the screen. Once it's on the screen, that is no way basically to move the annotation but to delete it and add a new one with new coordinates.
My first location using Core Location is almost always invalid.
My code is as follows:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
//for saving the data ACCURATELY for calculations
// make sure the coordinates are valid
if ([self isValidLocation:newLocation withOldLocation:oldLocation])
{
mDistance = [newLocation distanceFromLocation:oldLocation];
[[NSNotificationCenter defaultCenter]postNotificationName:#"locationUpdated" object:nil];
}
}
As you can see it checks to see if it is a valid location with isValidLocation. That code is here:
- (BOOL)isValidLocation:(CLLocation *)newLocation
withOldLocation:(CLLocation *)oldLocation
{
// Throw away first point
if (isFirstPoint)
{
NSLog(#"First point thrown away.");
isFirstPoint = NO; //subsequent updates will NOT be the first point
return NO;
}
// Filter out nil locations
if (!newLocation){
NSLog(#"New location invalid");
return NO;
}
if (!oldLocation)
{
NSLog(#"Old location invalid");
return NO;
}
// Filter out points by invalid accuracy
if (newLocation.horizontalAccuracy < 0)
{
return NO;
}
// Filter out points that are out of order
NSTimeInterval secondsSinceLastPoint = [newLocation.timestamp
timeIntervalSinceDate:oldLocation.timestamp];
if (secondsSinceLastPoint < 0){
return NO;
}
// Filter out points created before the manager was initialized
NSTimeInterval secondsSinceManagerStarted = [newLocation.timestamp
timeIntervalSinceDate:locationManagerStartDate];
if (secondsSinceManagerStarted < 0){
return NO;
}
// If the distance is negative
if ([newLocation distanceFromLocation:oldLocation] < 0)
{
return NO;
}
if(newLocation.speed < 0)
{
return NO;
}
// GIANT ELSE: The newLocation is good to use
return YES;
}
Even after checking all of that, my first point is always invalid. For example, I went from work to home, and turned on my location manager at home, yet my first coordinate was from my office at work. How can I fix this?
Here is what happens when I get an invalid first point:
It really depends on your use case. Core Location often returns the device's last known position in order to give you a result as quickly as possible. This location is passed to you before the device has finished acquiring a new location. The last known position can be several kilometers off your current position.
Depending on the type of your app, this might be a totally negligible difference (e.g. if an app just wants to locate the country a user is in) or it might represent an inacceptable error. Core Location can't tell.
It's important for you to decide how to deal with this behavior. Always throwing the first reported location away might not be the best strategy. You might want to store the time when you call startUpdatingLocation and only throw the first reported location away if the system passes it to you within a very brief period of time (say, 1/10th of a second) that makes it likely to be a cached location. Also, the location's timestamp property might be helpful in judging how (in)accurate the reported location can be.
Your test is wrong. The documentation of locationManager:didUpdateToLocation:fromLocation: clearly states that for the first update, the oldLocation is nil. But you don't test for that: you only look at newLocation and then access oldLocation. This can lead to bad values or crashes.
I am using the CoreLocation framework to get my speed and distance to calculate average speed.
On the first update that CoreLocation sends out, it shows negative values for both speed and distance traveled. How can I fix this?
Speed is locationController.locationManager.location.speed where locationController holds my CoreLocation delegate. Distance is calculated by taking the old location and the new location and calculating distance.
//Distance
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// make sure the old and new coordinates are different
if ((oldLocation.coordinate.latitude != newLocation.coordinate.latitude) &&
(oldLocation.coordinate.longitude != newLocation.coordinate.longitude))
{
mDistance = [newLocation distanceFromLocation:oldLocation];
}
}
The data returned by Core Location may be invalid for a number of reasons. Before you use the data, run this method to see if it is valid.
// From http://troybrant.net/blog/2010/02/detecting-bad-corelocation-data/
- (BOOL)isValidLocation:(CLLocation *)newLocation
withOldLocation:(CLLocation *)oldLocation
{
// filter out nil locations
if (!newLocation){
return NO;
}
// filter out points by invalid accuracy
if (newLocation.horizontalAccuracy < 0){
return NO;
}
// filter out points that are out of order
NSTimeInterval secondsSinceLastPoint = [newLocation.timestamp
timeIntervalSinceDate:oldLocation.timestamp];
if (secondsSinceLastPoint < 0){
return NO;
}
// filter out points created before the manager was initialized
NSTimeInterval secondsSinceManagerStarted = [newLocation.timestamp
timeIntervalSinceDate:locationManagerStartDate];
if (secondsSinceManagerStarted < 0){
return NO;
}
// newLocation is good to use
return YES;
}
There's a note in the CLLocationManager Class Reference:
Because it can take several seconds to return an initial location, the location manager typically delivers the previously cached location data immediately and then delivers more up-to-date location data as it becomes available. Therefore it is always a good idea to check the timestamp of any location object before taking any actions.
You should check whether you're getting a cached value and ignore it, waiting for the first "real" update.
NSTimeInterval timeSinceLastUpdate = [[newLocation timestamp] timeIntervalSinceNow];
// If the information is older than a minute, or two minutes, or whatever
// you want based on expected average speed and desired accuracy,
// don't use it.
if( timeSinceLastUpdate < -60 ){
return;
}
If you are collecting the first point, it has no reference to calculate speed or distance. I believe it is defined to return -1 if it can't get you what you need.
To resolve this, simply check for the negative values.
if(location.speed > 0) {
return;
}
I am using the instance method distanceFromLocation in order to compare my new location with const defined locations
I am giving CLLocation *bonuslocation an instant value which is one of the gps points i am interested in and then i compare it to the new location
if the distance is less than 20m from the point an audio file is played.
While this is working perfectly for one location it does not work at all
if i add locally into the updatelocationmanager function more than one..
The code:
CLLocation *bonuslocation = [.....]
CLLocationDistance distancea = [bonuslocation distanceFromLocation newlocation]
if (distancea <= 20)
{
//play an audio
}
Can i have some advice on how to do it for 10 gps points????
Today is my Birthday can you see that as a birthday present??
Thank you..
Why not just put it in a loop? Or just run the comparison on 10 locations? What exactly is it that isn't working?
EDIT:
You never mentioned where you're getting your other locations, so let's assume you make them somehow and store them in an array...
NSArray *locationArray;
I gathered from your comment that you have different sounds for each location? A simple way would be to store the sounds in a second array...
NSArray *soundsArray;
Then you can do the following in your locationManager:didUpdateToLocation:fromLocation:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
for(int i=0; i<[locationArray count]; i++){
CLLocation *location = (CLLocation *)[locationArray objectAtIndex:i];
if([newLocation distanceFromLocation:location] < 20.0){
//perform some action e.g.
//play sound at [soundArray objectAtIndex:i]
}
}
}
Although I don't recommend simply playing a sound, as this simple logic will cause the sound to be played once for every location within the threshold all at the same time.
I need to track user current location with realtime refreshrate
I have one function with two solutions for that.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
# ifdef Variant_1
if(m_currentLocation)
[m_Map removeAnnotation:m_currentLocation];
else
m_currentLocation = [MKPlacemark alloc];
[m_currentLocation initWithCoordinate:newLocation.coordinate addressDictionary:nil];
[m_Map addAnnotation:m_currentLocation];
[m_Map setCenterCoordinate:m_currentLocation.coordinate animated:YES];
# else //Variant_2
if(m_currentLocation == nil)
{
m_currentLocation = [MKPlacemark alloc];
[m_currentLocation initWithCoordinate:newLocation.coordinate addressDictionary:nil];
[m_Map addAnnotation:m_currentLocation];
}else
{
[m_currentLocation initWithCoordinate:newLocation.coordinate addressDictionary:nil];
//[m_currentLocation setCoordinate:newLocation.coordinate];
}
[m_Map setCenterCoordinate:m_currentLocation.coordinate animated:YES];
# endif
}
Variant_1 works good but when you move fast the location sing on the map blinks.
Variant_2 does not blink but does not move location sing however moves map.
Where is the problem?
In Variant_1, it probably blinks because you're doing a removeAnnotation and then an addAnnotation instead of just modifying the coordinates of the existing annotation.
In Variant_2, initWithCoordinate returns a new MKPlacemark object with those coordinates. It doesn't update the properties of the object you are calling the method on.
What happens if you run the setCoordinate line instead?
A separate question is why not use the MKMapView's built-in ability to show the current user location? Just do m_Map.showsUserLocation = YES; at the start. You don't need CLLocationManager to get the user's current location if you are using the MKMapView anyway.
I think you'll still need to center the map on the user's current location using one of the map view delegate methods:
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
[mapView setCenterCoordinate:userLocation.location.coordinate animated:YES];
}