I'm using MKMapView and I start the map at the last known location with CLLocationManager, the problem is that the iPhone and Location Services reports that I'm still using the services after I'm done which rises some concerns about battery usage.
So, please help me release this properly.
CLLocationManager * MANG = [[CLLocationManager alloc] init];
[MANG startMonitoringSignificantLocationChanges];
if(MANG.location){
[mapa setCenterCoordinate:MANG.location.coordinate animated:NO];
}
[MANG stopMonitoringSignificantLocationChanges];
[MANG stopUpdatingLocation];
[MANG release];
There are two ways to fetch the location using Location Services: the first one, less accurate but more battery friendly; and the second one more accurate.
When you declare [myLocationManager startMonitoringSignificantLocationChanges] your iPhone checks for location every time you left a cell tower and enter into a new one.
When you declare [myLocationManager startUpdatingLocation] your iPhone checks for location every time the GPS detects a position change (maybe each 1-3 meters, depending on accuracy).
So the thing is, in your code you’re trying to stop the declared Location Manager twice. Just remove the second stop instruction and you’ll get the correct code:
CLLocationManager * MANG = [[CLLocationManager alloc] init];
[MANG startMonitoringSignificantLocationChanges];
if(MANG.location){
[mapa setCenterCoordinate:MANG.location.coordinate animated:NO];
}
[MANG stopMonitoringSignificantLocationChanges];
[MANG release];
Related
I recently started testing my app on an iPhone 5, and to my alarm, it seems that the CLLocationManager doesn't really work! Although [CLLocationManager headingAvailable] is YES, I don't receive any heading updates at all. Strangely, on an iPhone 4, after 30 or so heading updates, locationManager:didUpdateToHeading: is no longer called. This issue is entirely new. The location manager also returns negative numbers for verticalAccuracy, so I'm assuming the altitude it is invalid. Here's how I'm creating the location manager:
CLLocationManager* locationManager = [[CLLocationManager alloc] init];
if([locationManager respondsToSelector:#selector(disallowDeferredLocationUpdates)]) {
[locationManager disallowDeferredLocationUpdates];
[locationManager setPausesLocationUpdatesAutomatically:NO];
}
locationManager.headingOrientation = CLDeviceOrientationFaceUp;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.headingFilter = -1;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[sharedSingleton setLocationManager:locationManager];
sharedSingleton is just my singleton class that handles some odds and ends, including holding onto a reference to the location manager.
If I need to post any more code let me know. I just don't know what might be causing this strange issue. Thanks!
You need to retain "locationManager" in memory somewhere, either as a property of your object or as an instance variable.
What I belive is happening is that you're creating your location manager, and then your method exits and "locationManager" falls out of scope and is magically released by ARC.
So, instead, do something like this:
in your #implementation:
#property (strong) CLLocationManager * locationManager;
and in your #interface:
self.locationManager = [[CLLocationManager alloc] init];
if([self.locationManager respondsToSelector:#selector(disallowDeferredLocationUpdates)]) {
[self.locationManager disallowDeferredLocationUpdates];
[self.locationManager setPausesLocationUpdatesAutomatically:NO];
}
self.locationManager.headingOrientation = CLDeviceOrientationFaceUp;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.headingFilter = -1;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
You could try a few things. First of all, I don't see a startUpdatingHeading call. Maybe you're doing it somewhere else. You should add the locationManager:didFailWithError: method to the delegate to check for errors, and try returning YES in locationManagerShouldDisplayHeadingCalibration: in case it's a calibration issue.
Seems the solution was obvious and I overlooked it. The delegate was being set to nil just moments after the location manager was started, which explains why on a slower device like the iPhone 4 a few updates were able to come through before the code setting the delegate to nil was run, but on the iPhone 5 it was instantaneous.
I have an application in which user track his/her route when jogging or cycling, So i need perfect location, so user's routes will be perfect.
But, I have one problem in this,
locManager = [[CLLocationManager alloc] init];
[locManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locManager setDelegate:self];
[locManager startUpdatingLocation];
In viewDidLoad. Using this didUpdateToLocation method called multiple times when I just dont move device a little and on map very strange route draw.
I just cant understand why this happen, if I am doing some wrong or missing something.
Thanks.......
I use locationManager.distanceFilter = 500; (or so) // meters
to prevent multiple calls from happening. just remember to call this BEFORE you start updating your location
You can set the distancefilter of the location manager hope this may help you
locationManager=[[CLLocationManager alloc] init];
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
locationManager.distanceFilter=10.0;
[locationManager startUpdatingLocation];
When you first start location services, you'll generally see multiple location updates come whether you're moving or not. If you examine the horizontalAccuracy of the locations as they come in, you'll see that while it's "warming" up it will show a series of locations with greater and greater accuracy (i.e. smaller and smaller horizontalAccuracy values) until it reaches quiescence.
You could disregard those initial locations until horizontalAccuracy falls below a certain value. Or, better, during start up, you could disregard the previous location if (a) the distance between a new location and the old location is less than the horizontalAccuracy of the old location and (b) if the horizontalAccuracy of the new location is less than that of the prior location.
For example, let's assume you're maintaining an array of CLLocation objects, as well as a reference to the last drawn path:
#property (nonatomic, strong) NSMutableArray *locations;
#property (nonatomic, weak) id<MKOverlay> pathOverlay;
Furthermore, let's assume your location update routine is just adding to the array of locations and then indicating that the path should be redrawn:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"%s", __FUNCTION__);
CLLocation* location = [locations lastObject];
[self.locations addObject:location];
[self addPathToMapView:self.mapView];
}
Then the addPathToMapView can therefore remove the second from last location if it's less accurate than the last one and if the distance between them is less than the most recent location's accuracy.
- (void)addPathToMapView:(MKMapView *)mapView
{
NSInteger count = [self.locations count];
// let's see if we should remove the penultimate location
if (count > 2)
{
CLLocation *lastLocation = [self.locations lastObject];
CLLocation *previousLocation = self.locations[count - 2];
// if the very last location is more accurate than the previous one
// and if distance between the two of them is less than the accuracy,
// then remove that `previousLocation` (and update our count, appropriately)
if (lastLocation.horizontalAccuracy < previousLocation.horizontalAccuracy &&
[lastLocation distanceFromLocation:previousLocation] < lastLocation.horizontalAccuracy)
{
[self.locations removeObjectAtIndex:(count - 2)];
count--;
}
}
// now let's build our array of coordinates for our MKPolyline
CLLocationCoordinate2D coordinates[count];
NSInteger numberOfCoordinates = 0;
for (CLLocation *location in self.locations)
{
coordinates[numberOfCoordinates++] = location.coordinate;
}
// if there is a path to add to our map, do so
MKPolyline *polyLine = nil;
if (numberOfCoordinates > 1)
{
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfCoordinates];
[mapView addOverlay:polyLine];
}
// if there was a previous path drawn, remove it
if (self.pathOverlay)
[mapView removeOverlay:self.pathOverlay];
// save the current path
self.pathOverlay = polyLine;
}
Bottom line, just get rid of locations that are less accurate than the next one you have. You could get even more aggressive in the pruning process if you want, but there are tradeoffs there, but hopefully this illustrates the idea.
startUpdatingLocation
Will continuously update a user's location even when the location does not change. You just need to structure your app to handle these continuous updates according to your needs.
Try reading Apple's documentation on this subject. It is confusing at first but try anyway.
http://developer.apple.com/library/ios/#documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html#//apple_ref/doc/uid/TP40009497-CH2-SW1
I think this is what you need.startMonitoringForRegion:desiredAccuracy
for Example see the following github link.
Try this Bread Crumb sample code provided by Apple..
http://developer.apple.com/library/ios/#samplecode/Breadcrumb/Introduction/Intro.html
Add this,
[locManager stopUpdatingLocation];
into your updateUserLocation delegate method.
Review the following code snippet:
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
[_locationManager stopUpdatingLocation];
}
locationManager.startUpdatingLocation() fetch location continuously and didUpdateLocations method calls several times,
Just set the value for locationManager.distanceFilter value before calling locationManager.startUpdatingLocation().
As I set 200 working fine
locationManager.distanceFilter = 200
locationManager.startUpdatingLocation()
I'm trying a lot of things to stop the location update of my app but nothing seems work…
What I do (regard of the post : StopUpdatingLocation method not working for iOS5) :
// Initialise my locationManager and start monitoring :
locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];
// .. Some code to use the coordinates that locationManager gives me.
// To stop monitoring :
locationManager = nil;
You have to know I placed [locationManager stopUpdatingLocation]; in the method :
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
So the location is updated only 1 time (btw tell me if it's a good idea…).
I also tried to place [locationManager stopUpdatingLocation]; just before locationManager = nil; in the main code, but the blue dot that gives me my location is still moving on my map in both cases…
I also set a timer which print the locationManager object in the console, and it gives me (null) meanwhile the blue dot is still moving on my iPhone 5 so I don't understand that…
Or maybe the dot is still moving because of another thing, but not because of locationManager update ?
I'm certainly missing something but I don't get what :/.
Thanks for ideas and help.
One possibility: The blue dot moving on your map is because you set the MKMapView's showsUserLocation to YES. It will track until you set it to NO.
Another possibility: This line is wrong:
locationManager = nil;
That does not stop monitoring, but it does cause you to be unable to refer to the location manager, so now you can't stop monitoring! Cut that line.
I faced the same problem that even after I placed the code
[locationManager stopUpdatingLocation];
locationManager=nil;
my application was using GPS service which was un-necessarily consuming battery power. the solution for this problem is to turn off the showUserLocation property of MKMapView .
[self.mapView setShowsUserLocation:NO];
Since the MKMapView keeps on using your GPS service even if the LocationManager is nil.
Hope it will help you
Use this lines of code
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;
Thanks!
Here is my code:
- (void) viewWillAppear:(BOOL)animated
{
// SETUP THE LOCATION MANAGER.
self.locManager = [[CLLocationManager alloc] init];
self.locManager.delegate = self;
[self.locManager startUpdatingLocation];
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.locManager stopUpdatingLocation];
[self.locManager.delegate release];
}
When the View Controller exits the CLLocationManager arrow logo in the top right corner is still showing. This is both on iOS 4.3 and 5.0. Any explanation?
I believe the system indicates the location badge on any app that has used Core Location in last hour or so.
The purple arrow should disappear as soon as you call:
[self.locManager stopUpdatingLocation];
While allocating your locManager, you need not call self.locManager. That will bump up the retain count to 2. Instead use:
locManager = [[CLLocationManager alloc] init];
Also, put a breakpoint in your viewWillDisappear: method and make sure it does get called. Also, set the delegate to nil at the end.
After following these points, your code shall work.
The purple arrow is for Location Services and consumes battery heavily. Make sure the arrow disappears as soon as you call stopUpdatingLocation:
I have a MKMapView whereby I drop an annotation everytime the view loads, or when showLocation custom class method is called.
I need the accuracy to be the best
-(void)viewDidLoad {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[locationManager startUpdatingLocation];
}
-(IBAction) showLocation:(id) sender{
[locationManager startUpdatingLocation];
}
- (void) locationManager:(CLLocationManager *) manager
didUpdateToLocation:(CLLocation *) newLocation
fromLocation:(CLLocation *) oldLocation {
// start geocoding with newLocation coordinate which will automatically set annotation.
SVGeocoder *geocodeRequest = [[SVGeocoder alloc]
initWithCoordinate:CLLocationCoordinate2DMake(newLocation.coordinate.latitude, newLocation.coordinate.longitude)];
[geocodeRequest setDelegate:self];
[geocodeRequest startAsynchronous];
[geocodeRequest release];
[locationManager stopUpdatingLocation];
}
My question is when will the didUpdateToLocation method be called? Only after a new location is found when I perform [locationManager startUpdatingLocation]?
I am facing some weird issue when the user is travelling and on stationary.
Say the user is travelling from point A->B->C->D with 1 min intervals between points. When I call my method at point C, sometime it returns the coordinates of point A, sometimes point B and sometimes C. It's just random.
It's even more weird when I am on stationary. I get different coordinates when I calls showLocation method even though I am hooked up on my house WiFi.
I was thinking of implementing the didUpdateToLocation to get the best result it can within 5secs. If within the 5secs, it finds a particular location of an accuracy I had defined, then use the coordinate. If not, use the best it has found within the 5sec time frame. But as I am new I am not sure how to code something like that. I read up NSTimer and it seems like it might work.
Any advices guys?
Thanks a lot in advance!
One of the reasons you are receiving the location from point A is that CoreLocation is returning the last valid location it had first until it can obtain a more accurate location. When you call [locationManager startUpdatingLocation]; it will return the -didUpdateToLocation over and over until you are statisfied and finally call -stopUpdatingLocation.
I think you just need to allow a bit of time for it to get a better location fix before you stop updating your location. I would consider moving the stop updating location from your -didUpdateToLocation to a different method.
Remove [locationManager stopUpdatingLocation]; from your code and try .