I need once the app is launch, to check the location and send it to the server. After it, i need to check the location every kilometer.
So when i started the location update, i set the distanceFilter to none and on the first location receive, i changed it to 1 kilometer.
//If the location update is denied
if ([CLLocationManager authorizationStatus]==kCLAuthorizationStatusDenied)
[ self locationUpdateDenied:basicViewController];
else if ([CLLocationManager locationServicesEnabled]) {
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.distanceFilter=kCLDistanceFilterNone;
//In ViewDidLoad
if([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[_locationManager startUpdatingLocation];
}
The first location receive:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
if (locations>0) {
[_locationManager setDistanceFilter:1000.0f];
CLLocation *location = [locations objectAtIndex:0];
[User sharedInstance].latitude=location.coordinate.latitude;
[User sharedInstance].longitude=location.coordinate.longitude;
/* if (!_delegate) {
[_delegate userLocationUpdated];
}*/
}
}
the problem it keeps checking the location. The location isn't changing but it still gets to the didUpdateLocations. It like the distanceFilter isn't changing.
should i need to stop the location update and reactive it with the kilometer distanceFilter?
From the documentation i presume that you can set the distanceFilter property before you start the location service since you will be called immediatley after you start the service with startUpdatingLocation with a first location.
[manager setDistanceFilter:1000.0];
[manager startUpdatingLocation]; // will call didUpdateLocations immediatley
// with the current location
Related
In my current project.
I need user's location at every 50 meter user move.
So Basically After open application every 50 meter change I need user location for call web service in Objective c. Also i want same process run when application is in background state.
Thanks in advance
You have to make object of CLLocationManager when application starts and set it's delegate
Add the below code to get user's current location
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
Now add the delegate of CLLocationManagaer that is didUpdateToLocation and add the following code in that.
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
if(meters==50)
{
// CALL YOU WEBSERVICE
}
set your location track in
//create location manager object
locationManager = [[CLLocationManager alloc] init];
//there will be a warning from this line of code
[locationManager setDelegate:self];
//and we want it to be as accurate as possible
//regardless of how much time/power it takes
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//set the amount of metres travelled before location update is made
[locationManager setDistanceFilter:50];
and add
if ([CLLocationManager locationServicesEnabled]) {
[self.locationManager startUpdatingLocation];
}
Update
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = locations.lastObject;
NSLog(#"%#", location.description);
//In here you get all details like
NSLog(#"latitude = %#",location.coordinate.latitude);
NSLog(#"longitude = %#",location.coordinate.longitude);
NSLog(#"altitude = %#",location.altitude);
NSLog(#"horizontalAccuracy = %#",location.horizontalAccuracy);
NSLog(#"verticalAccuracy = %#",location.verticalAccuracy);
NSLog(#"timestamp = %#",location.timestamp);
NSLog(#"speed = %#",location.speed);
NSLog(#"course = %#",location.course);
}
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 have a code in a UIViewController that starts the location update:
[locationManager startUpdatingLocation];
Is working perfectly. But I need every time you exit this screen it stops updating the location and start again when I return.
The first time it for updates. In other times it does not stop.
Code for exit from view:
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
Ihave tried also: (without success too)
[locationManager stopMonitoringSignificantLocationChanges];
[locationManager stopUpdatingHeading];
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
locationManager = nil;
It always update. But from the second time not stop update.
didUpdateLocation code:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
[self addingMarkerUser];
}
You should put your code in the viewDidAppear and i suppose in your [self addingMarkerUser] you use something like this without the stop (if not, please provide the code) :
CLGeocoder *geocoder = [[CLGeocoder alloc] init] ;
[geocoder reverseGeocodeLocation:_currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (!(error)) {
//do something with the data.
//then stop the update.
[locationManager stopUpdatingLocation];
}
}];
If you do like that, every time your view appear, the location will start the update then stop once the data retrieve.
I identified a strange behaviour on my app using CoreLocation. I'm using the region monitoring functionality but, after authorising the location services (via popup or settings->Location Services) region monitoring fails (The operation couldn’t be completed. kCLErrorDomain error 5.). If I close the app and restart (therefore already authorised) everything works as expected.
My code looks like this:
-(void)initializeLocationServices
{
NSLog(#"Started location services");
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.pausesLocationUpdatesAutomatically = NO;
[locationManager startUpdatingLocation]; // to show authorisation popup
}
-(CLCircularRegion*)createRegion
{
// Test coordinates
CLLocationDegrees latitude = 50;
CLLocationDegrees longitude = -1;
CLLocationDistance radius = 50; // meters;
// If radius is too large, registration fails automatically, so limit the radius to the maximum value
if (radius > locationManager.maximumRegionMonitoringDistance) {
radius = locationManager.maximumRegionMonitoringDistance;
}
CLCircularRegion* region = [[CLCircularRegion alloc] initWithCenter:CLLocationCoordinate2DMake(latitude, longitude) radius:radius identifier:#"TEST"];
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
NSLog(#"Created region");
return region;
}
-(void)monitorProximity
{
CLRegion *region = [self createRegion];
// Check if support is unavailable
if ( ![CLLocationManager isMonitoringAvailableForClass:[CLRegion class]]) {
NSLog( #"Failed to initialise region monitoring: support unavailable");
return;
}
// Check if authorised
if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
NSLog( #"Failed to initialise region monitoring: app not authorized to use location services");
return;
} else {
NSLog(#"Started monitoring proximity");
}
// Clear out any old regions to prevent buildup.
if ([locationManager.monitoredRegions count] > 0) {
for (id obj in locationManager.monitoredRegions)
[locationManager stopMonitoringForRegion:obj];
}
[locationManager startMonitoringForRegion:region];
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region
{
NSLog(#"Started monitoring for region: %#", [region description]);
[locationManager requestStateForRegion:region]; // check if already inside region
}
-(void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
NSLog(#"Failed to start monitoring for region: %#", [error localizedDescription]);
}
-(void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
NSLog(#"didDetermineState");
if (state == CLRegionStateInside) {
NSLog(#"inside");
return;
} else if (state == CLRegionStateOutside) {
NSLog(#"outside");
} else {
NSLog(#"unknown");
}
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(#"didEnterRegion");
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"didExitRegion");
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
NSLog(#"Monitoring authorisation status is now: %#", status == kCLAuthorizationStatusAuthorized ? #"authorized" : #"not authorized");
if (status == kCLAuthorizationStatusAuthorized) {
[self monitorProximity];
}
}
Am I doing something wrong here? Do I have problems with the flow after didChangeAuthorizationStatus gets called?
From other user reports, it seems that kCLErrorDomain 5 is a 'catch all' for region monitoring fails; it doesn't provide much useful information. I believe that your issue is being caused by the line
[locationManager requestStateForRegion:region]; // check if already inside region
which you're calling from inside the delegate method didStartMonitoringForRegion:
I saw something very similar in my own project and taking this line out (or delaying its execution for a while) solved the issue. My best guess is that iOS is still doing running some internal region monitoring code when this delegate method fires, so it's not an appropriate time to call requestStateForRegion:
Try taking this out and see if it is the answer.
kCLErrorDomain code/error 5 means that you have tried to monitor more than 20 CLRegions.
Descriptio here
see startMonitoringForRegion description It says:
An app can register up to 20 regions at a time. In order to report region changes in a timely manner, the region monitoring service requires network connectivity.
kCLErrorDomain 5 is a catch all that can mean many different things.
One of the sources is when you call [locationManager requestStateForRegion:region] which is necessary when you first monitor for a region to know if you're already in the region or not. This is because the didEnter region will only be called when you actually enter the region. Usually this means the first time you monitor for the region, you must wait 5 seconds until the region is not detected, and only then will didEnter region fire off the next time you're in the region.
There are many different reports of causes to the problem:
Ensure no more than 20 beacons are being monitored
5 means "regionMonitoringFailure". Ensure the radius is not too large (not relevant for beacon monitoring).
Ensure location updates are registered
Omit calling requestStateForRegion, however I described above why it's necessary to do so.
Restarting device and bluetooth may help
Try with 30 second delay
None of these worked for me, however. I think my root cause was similar to the iOS 7.1 bug where it just randomly stopped working on some devices. I tried the restart and restart of bluetooth, nothing helped.
Not sure what changed, but I just tried again the next day and it started working.
Basically you may want to try a different device until this one starts working again.
I have a CoreLocation manager in VC, when user pressed "get direction" button, I initalize location manager, and app opens google map direction with current location and some pre defined destination location.
Here is my problem, if app is not in background state, current location nearly always true, bu if app calling from background in same VC and user pressed again "get direction" button , current location generally shows old locations. In short, I'm troubling with multitasking and timestamp of retrieved locations did not solved my problem.
IBAction:
if ( self.locationManager ) {
[_locationManager release];
self.locationManager = nil;
}
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationTimer = [NSTimer scheduledTimerWithTimeInterval:LOCATION_TIMER target:self selector:#selector(stopUpdatingLocationTimer) userInfo:nil repeats:NO];
HUD = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
[self.locationManager startUpdatingLocation];
Core Location Delegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"%f",locationAge);
if (locationAge > 3.0)
return;
if (newLocation.horizontalAccuracy < 0)
return;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy ) {
self.currentLocation = newLocation;
if (self.currentLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy) {
[self stopUpdatingLocations:YES];
}
}
}
In your example locationAge is a negative representation of the number of seconds since the timestamp of newLocation. This means that locationAge will never be greater than 3 and you're effectively letting every update through the sieve.
Set locationAge like this:
NSTimeInterval locationAge = [newLocation.timestamp timeIntervalSinceNow];
For those who encounter same problem,
Also, some tutorials related with core location on web, lead me this problem.
Of course, I keep CLLocation ivar in my VC, whenever CLLocation ivar
sets and google maps called, my app goes to background.
Then, my app calls from background by user, and start updating locations,
and old CLLocation ivar is not nil and probably best horizantal accuracy then
newly comes. Therefore;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy )
this line cause problems, and old location in CLLocation ivar
never replaced.
So I changed viewDidDisappear like this and I assigned nil value to CLLocation variable and works perfectly.
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.locationManager stopUpdatingLocation]; // CLLocationManager
self.locationManager = nil;
[self.locationTimer invalidate]; // NSTimer
self.locationTimer = nil;
self.currentLocation = nil; // CLLocation
}
p.s : thank you Mark Adams