ios CLLocationManager won't get location second time - objective-c

I have a getLocation method that initializes my CLLocationManager and calls startUpdatingLocation. After I get the user's location, I call stopUpdatingLocation.
Later, when the user presses refresh, I call a method reloadData which calls getLocation so I can get the user's latest location. However, this never calls the locationManager:didUpdateToLocation:fromLocation
method.. so I never get the user's latest location. What could be the issue?
-(void) getLocation {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
}
- (void) locationManager: (CLLocationManager *)manager
didUpdateToLocation: (CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if (oldLocation!= nil) { // make sure to wait until second latlong value
[self setLatitude:newLocation.coordinate.latitude];
[self setLongitude: newLocation.coordinate.longitude];
[self.locationManager stopUpdatingLocation];
self.locationManager.delegate = nil;
self.locationManager = nil;
[self makeUseOfLocationWithLat:[self getLatitude] andLon:[self getLongitude]];
}
}
-(void) reloadData {
[self getLocation];
}

Is it really necessary to allocate a new CLLocationManager? Try just allocate it once (in your init for example) and just call startUpdatingLocation and stopUpdatingLocation on demand.
For me, this solution works great.

Do you move during testing this? Because I think the callback will only be triggered, when:
you call startUpdatingLocation
your location changes
the location manager gets better results (more detailed)
So I think for your use-case: as you don't move, the callback locationManager:didUpdateToLocation:fromLocation: will only be called once after you hit refresh and as there is no old location, you will not go into the if case.
Another thing: you should definitely have only one CLLocationManager in your class. I only use one per project/application (wrapped in a singleton). This is the preferred way to do! Also I think this will retain the oldLocation value so that your problem may be resolved by changing this.
Best,
Christian

you can try this ,this will help u to update for every time when open the page.Cause if u put startUpdatingLocation in viewdidload ,it will get load only for the first time
-(void)viewWillAppear:(BOOL)animated
{
[locationManager startUpdatingLocation];
}

Related

didUpdateLocations does not get called when app enters foreground, core location, ios

my goal is whenever app enters fore ground, i will fetch the location to update my weather forecast. What I do is
- (void)viewDidLoad
{
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
}
- (void)viewWillAppear:(BOOL)animated
{
self.locationManager.delegate = self;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
}
#pragma mark - Click to get weather
-(void)enterForeground {
[self.locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog#"didUpdateLocations";
}
However, enterForeGround does get call whenver I enter fore ground but didUpdateLocations doesnot get called all the time.
I dont know what I am missing some crucial things for location service. Please advice me if you have any ideas.
Thanks
There is never a guarantee that didUpdateLocations will be called. The thing you can do is when viewDidLoad is called, you can request que last location with. self.locationManager.location.
You can now check the timestamp and the precision of that location. If the data is too old or innacurate for your needs, you then call startUpdatingLocation, and when you get a fix according to your filter and accuracy, didUpdateLocations will be called.
First you need to add Location Services in background by going to Targets -> Capabilities and under "Background Modes" check on "Location Updates".
Secondly you need to start location update [self.locationManager startUpdatingLocation] somewhere appropriately (for you code provided above in viewWillAppear seems to be the best choice)
- (void)viewWillAppear:(BOOL)animated
{
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation]
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
}
Now when you app enter background mode and reenter Foreground, the locationManager delegate method should be called.

Deferring Location Updates in Background

I have a app which collects location data in foreground and background. To save battery i want to use the allowDeferredLocationUpdatesUntilTraveled property as explained in Apple Doc
From the documents, allowDeferredLocationUpdatesUntilTraveled gets set(based on time and distance) in foreground. Once app goes in the background we won't receive regular location updates instead we receive them based on the allowDeferredLocationUpdatesUntilTraveled.
I have implemented following code but the deferring does not get called in the background.
#pragma mark - Location Manager
-(void) setLocationManager
{
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
-(void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"didUpdateLocations");
if (!deferringUpdates)
{
CLLocationDistance distance = 200;
NSTimeInterval time = 60;
[locationManager allowDeferredLocationUpdatesUntilTraveled:distance timeout:time];
deferringUpdates = YES;
}
}
-(void)locationManager:(CLLocationManager *)manager didFinishDeferredUpdatesWithError:(NSError *)error
{
NSLog(#"didFinishDeferredUpdatesWithError");
}
SetLocationManager gets called in the foreground and works fine. Once app goes in the background i still receive regular location updates rather than allowDeferredLocationUpdatesUntilTraveled.
I have also set the following values in the info.plist file
Background Fetch
Background Location Updates
Device Capabilities - location service
Anyone luck with implementing this?
You need to set deferringUpdates back to NO within didFinishDeferredUpdatesWithError : as per Apple documentation, the "delegate’s locationManager:didFinishDeferredUpdatesWithError: method is called exactly once for each time you call (allowDeferredLocationUpdatesUntilTraveled)".
Thus allowDeferredLocationUpdatesUntilTraveled is only called once until deferringUpdates is NO.

CLLocationManager updates only on Simulator Not on Devices

Here we have to update the current location by using the location manager,and its correctly updating on simulator but its not updating on device only 4 or 5 times only repeated.why the location is not updated frequently kindly hep me to solve this problem
Here i used code is showed below
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[locationManager startUpdatingLocation];
Delegate Method:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(#"newLocation: %#",newLocation);
}
This is the delegate method is calling four or five times.
If you are using location accuracy as 'kCLLocationAccuracyBestForNavigation', your device should remain plugged in.
Better you set it as 'kCLLocationAccuracyBest'. Also move to significant distance to hit the delegate. initially it will hit 4-5 times to locate you. Once your location is identified, it will call the delegate when there will be change in your location.
So, in delegate write something in file stored in documents directory in append mode. log the lat/long and Time details into it. Now move for some distance.
Join the mobile and get the file from documents directory. It must have logg the required details.
Here i solved this problem using this delegate method
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations{
}

Delegation and retrieving info on IOS

I'm trying to get heading info from CLLocationManager but it's not getting called. I did everything as the documentation says, but something is very wrong.
I'm using locationManager delegating into my app delegate.
Here is the method to retrieve heading messages:
- (void) locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
NSLog(#"%#", newHeading);
}
Here is the part from main()
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager startUpdatingHeading];
But nothing happens! With debugging, NSLog is never getting called.
When I do same with [locationManager startUpdatingLocation] everything works fine, shows the location info, using another method (very same looking but using
- (void) locationManager:(CLLocationManager *) manager
didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
but I need heading info here.
Found the deal.
Code is perfectly fine, the issue is in Iphone simulator.
Somehow it is providing location info just fine, but heading info is not provided thus the message is never sent.
Talk about weird things, apple.

Scope of an object, objective-c, CLLocationManager

I'm still pretty new to programming so I have somewhat of a noob question. When you have an instance variable, in my case of type CLLocationManager, in my appDelegate.m file, I thought I could allocate and initialize my CLLocationManager instance variable in the applicationDidFinishLaunching method. And then I could use a button to startUpdatingLocation in a different method (since I'm calling it from another class). This doesn't seem to work and I'm thinking that I needed to alloc/init in the same method I startUpdatingLocation. Is that true? Do I need to stopUpdatingLocation in the same method? My code is below:
(locationManager is declared as a property)
- (void)stopUpdating {
[locationManager stopUpdatingLocation];
}
- (double)distanceTraveled {
return distanceTraveled;
}
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch
[window addSubview:rootController.view];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[window makeKeyAndVisible];
}
- (void)startUpdating {
[locationManager startUpdatingLocation];
}
It seems like I should be doing it more like:
- (void)startUpdating {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
If I am supposed to do it this second way, is it because that the scope of the CLLocationManager object is only for the method it is in? I thought having it as an instance variable I would be able to use it in other methods and I could have a separate method for startUpdatingLocation and stopUpdatingLocation. Thanks.
What you originally thought is correct. If you have an instance variable that variable remains available to you throughout the life of the object (in this case your app delegate).
If what you're doing isn't working, it's because of some other issue. you don't need to allocate a new CLLocationManager each time you call startUpdating.