I am trying to get a users current location using CLLocationManager. It is all working fine however there is a bit of a delay while the app is finding the location and I need to wait for it to complete before allowing the user to send it. Is there some sort of completion handler for [locationManager startUpdatingLocation]; of should I just use a BOOL variable to keep track of it?
You can use CLLocationManagerDelegate method called
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
Related
Below are some snippets of my code
BOOL checkingForLocation;
.
.
.
- (IBAction)LocationButtonTapped:(id)sender {
[locationManager startUpdatingLocation];
checkingForLocation = YES;
}
.
.
.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
[locationManager stopUpdatingLocation];
// locationManager = nil;
if (checkingForLocation) {
checkingForLocation = NO;
NSLog(#"here");
// fetch data from server using location and present view controllers
}
}
didUpdateLocations is called multiple times because locationManager is continually updating the location per startUpdatingLocation. My app has a bug where the code within if(checkingForLocation) runs multiple times and renders the view multiple times causing undesired results.
1) Why is it that stopUpdatingLocation doesn't stop further calls to didUpdateLocations?
2) Furthermore, if the checkingForLocation has already been set to NO why does the subsequent calls to didUpdateLocations still treat checkingForLocation as YES. Is there a race condition there?
Through searching other SO questions, I found that setting locationManager = nil will stop the extra calls to didUpdateLocations, which it does fix the issue in my case, but no real explanation. It seems that stopUpdatingLocation should take care of that. Any insight is much appreciated.
Thank you,
didUpdateLocations: can be called frequently and at any time because of its async nature and optimisations :
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. If both
location services are enabled simultaneously, they deliver events
using the same set of delegate methods.
Actually, if you uncomment locationManager = nil; it should help, but if you want to use your checkingForLocation property, you should make the assignment synchronised. #synchronized(self) is the easiest way in this case.
I'm using google place API to get proper information of current place.
I used this code in the App and get success to fetch list of all nearby locations, but how can I recognize my exact current location from the list?
I read doc and find that we get current location from the list based on likelihoods (value between 0 to 1).
A higher value of likelihoods means a greater probability that the place is the best match.
But my current location is coming into this list but likelihoods value is not higher.
So I have two questions:
1) How can I recognize my exact current location? Any other setting is there or any alert-net way is there? (Without use of place picker)
2) If I leave current place then I want to perform some action so How can I get that I left this place recently? like checked-In/Out?
Google's API requires that you initialize a CLLocationManager. Since you already have a location manager, you can set your class to be a CLLocationManagerDelegate. This provides you with native iOS methods that mean you can get both an exact location and a notification that the location has changed
To get an exact location:
[self.locationManager requestLocation]; //Get the current location once (iOS 9 and above)
To monitor location:
[self.locationManager startUpdatingLocation] // Ask for the current location until you call stopUpdatingLocation
// or
[self.locationManager startMonitoringSignificantLocationChanges] // Tells you when your location has greatly changed
You then need to conform to the protocol, which has 2 methods at minimum:
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations
// Do anything that you need to do once you have a location update
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
// Your location update failed, handle it
I'm using a CLLocationManager to get a users location (primarily running in the background). I create it like so and set the accuracy to best lowest as to have minimal impact on battery.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
I then implement the delegate method:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
I'm running the application in the simulator and simulate a 'freeway drive'. The location manager delegate method seems to be updating every second which I'm thinking isn't correct as the 'car' is probably not travelling at 3km/sec (in fact it's travelling at 50km/hr).
Is my understanding of this functionality correct or am I missing something? Will this have a large negative impact on battery life? Would this change in real life usage depending on cell tower/GPS/wifi signals?
I am trying to get the users location if user is getting or making a phone call. I can use the CTCallCenter for my calling events.
The if one of the states are firing i am trying to get the location...It works because i see the arrow in top right corner...
But i don´t get a callback from CLLocationmanager:
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
Does somebody know´s why?
UPDATE: Just found the Solution by myself..I have to init the CLLocationManager on the main Thread...it works now
Just found the Solution by myself..I have to init the CLLocationManager on the main Thread...it works now
At the bottom (in AppDelegate.m) you can see my CLLocationManager delegate methods, none of them get called. I'm using a GPX file, but even if the regions do not get entered or exited, the delegate method didStartMonitoringForRegion should be called.
SomeOtherClass.m
AppDelegate appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.locationManager startMonitoringForRegion:regionToMonitor desiredAccuracy:kCLLocationAccuracyNearestTenMeters];
AppDelegate.h
#interface AppDelegate : UIResponder <UIApplicationDelegate,CLLocationManagerDelegate>
#property (nonatomic, retain) CLLocationManager *locationManager;
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if (locationManager==nil) {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
}
return YES;
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
NSLog(#"Did enter region");
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
NSLog(#"Did exit region");
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Fail");
NSLog(#"%#", [error description]);
}
-(void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
NSLog(#"Did start monitoring for region: %#", region.identifier);
}
First of all you should add the following Location manager delegate method, and see if for some reason the region monitoring registration failed:
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(#"%#",error);
}
Second, the region monitoring is a system shared resource.
The documentation states that it allows you limited number of regions to monitor (not specifying any number unfortunately) and mentioning that if another app register additional regions to monitor, some of your apps monitored regions, might be discarded.
Third, region monitoring is not using any GPS technology. It only uses the cellular antenna of your network operator and whenever you change a cell tower, it fires an system event that loops through all monitored regions and see if a region is within the new area you are now located.
This means that you should expect less accuracy in the service and therefore you should increase the radius you are setting for a region.
Finally if your app is completely terminated and NOT suspended, then your app will receive in the app delegate inside the:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
a UIApplicationLaunchOptionsLocationKey in the launchOptions dictionary.
It's your responsibility then to reinitialize your location manager, get the current location and fire a local push notification to the user, within the limited time your application live state has.
As the app is not going to run normally at that stage, but in a limited background mode state.
Also if you want to test the app in the simulator, you should add a track.gpx file to your project and set the simulator to track mode.
Make sure that the 2 locations you put in the simulator are not very distant (as it might take quite long time for the tracking to complete) and set them in a path, where it will enter your monitored region.
Then see if you get any callbacks.
Do not test it with your device, as you need to actually walk a couple of blocks to see any real interaction with the device :-)
Not entirely sure why it wouldn't receive your callbacks. I'll cover a few things I'm noticing and you can see if they help.
You are not setting the desiredAccuracy or distanceFilter in your location manager. They should default to something, but if your locations in the GPX aren't within the accuracy of the regions, it could just be not getting close enough to trigger.
The method you are using to start monitoring has been deprecated in iOS 6. You can add the accuracy to the location manager and leave that off your call.
It would be helpful to see how you are creating your CLRegion to monitor, regionToMonitor. If it is being created ok as soon as you start monitoring, you should see the hollow purple location arrow show up. You should also receive the delegate call -didStartMonitoringForRegion. If neither of these are showing up, then you probably just have an issue with your location manager setup.
One suggestion would be to create your own location manager class and turn it into a singleton. This will prevent you from accidentally initializing multiple delegates and getting multiple calls. It also gives you one clean class to contain all your callback methods.
I don't see anything wrong with the code you've included, so I'm guessing the problem lies in the code you haven't included. Check to make sure your location manager code is being initialized and make sure your CLRegion is being created correctly. Hope this helps. I'll be happy to update my answer if you include more code and we find out what the true issue is.