Right now, I have it so when a button is clicked, it starts location services, sets the latitude/longitude variables. But location still continues to be running in the background.
I want is so when I click a button it finds the latitude/longitude, all location services stop.
Here's what I have currently.
- (IBAction)startButton:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
NSLog(#"%#", [self lat]);
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
[self setLat:[NSString stringWithFormat:#"%.6f", currentLocation.coordinate.latitude]];
}
}
Another problem is, if I instantly try to retrieve the value of the lat property, it returns null, most likely because it takes a second or two to find the location.
So I would also need to stop any further code to be run until the lat/long properties are set. For example, How would I stop the otherFunction from running until the latitude/longitude are found:
- (IBAction)startButton:(id)sender {
[self updateLocation];
[self otherFunction];
}
- (void)updateLocation
{
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
[self setLat:[NSString stringWithFormat:#"%.6f", currentLocation.coordinate.latitude]];
[locationManager stopUpdatingLocation]
}
}
Any help/ideas would be appreciated!
In your last function, after you verify that the currentLocation is not nil, then you should check for the accuracy of currentLocation, then call your setLat: function, then stop updating the location. See this post for more details:
CLLocationManager and accuracy issues - any experiences?
Related
In my iOS application, I have a table that uses your location to find data that is near you. I just installed it on my iPhone today, and when location services were needed, I got the expected alert that said "MyAppName would like to use your current location" and once I pressed OK, the app basically froze. When I closed the app and reopened it however, it worked perfectly fine. Now that I think about it, this happened on the simulator as well, as I have to run the app a couple times before location services works properly there too. Has this happened to anyone else, and do you know how to fix this? I don't want my users to have to close the app and reopen it for location services to work properly.
Here is some relevant code:
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"%#",error.userInfo);
if([CLLocationManager locationServicesEnabled]){
NSLog(#"Location Services Enabled");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Need Your Location"
message:#"Please go to Settings and turn on Location Services so you can see who's near you."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
_thisGeoPoint = [PFGeoPoint geoPointWithLatitude:currentLocation.coordinate.latitude
longitude:currentLocation.coordinate.longitude];
}
[locationManager stopUpdatingLocation];
located = true;
}
This is happening because locationManager stops running when it doesn't initially have permission. So you will need to re-run it once you detect that the permission has changed. You can check if the permission changed using the didChangeAuthorizationStatus delegate method.
So something like this:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
if (status == kCLAuthorizationStatusAuthorized) {
[locationManager startUpdatingLocation];
}
}
Below is code for my CLLocationManagerDelegate. I call the delegate methods using:
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
The delegate methods:
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
//get current location of phone:
if (newLocation != nil) {
_m.longitude = [NSString stringWithFormat:#"%.8f", newLocation.coordinate.longitude];
_m.latitude = [NSString stringWithFormat:#"%.8f", newLocation.coordinate.latitude];
_m.timestamp = newLocation.timestamp;
NSLog(#"didUpdateToLocation: %#", newLocation);
}
CLLocation *currentLocation = newLocation;
}
When I call the didUpdateToLocation method, I've verified through debugging that newLocation is not nil. _m is an object declared in my header, and is not nil either. The same is true for locationManager. However, when I try to set _m.latitude etc. and NSLog them, they all show up as (null). The didUpdateToLocation NSLog results in a line like this:
didUpdateToLocation: <+47.64312748,-122.12163262> +/- 65.00m (speed -1.00 mps / course -1.00) # 7/15/14, 9:26:07 AM Pacific Daylight Time
I'm not sure where I'm going wrong.
Your code looks correct. So probably you get null in logs because _m == nil.
I am using Core Location framework to getting location in iOS. I use, CLLocationManager *locationManager; and call [locationManager startUpdatingLocation];
Problem is I only need instantaneous location but startUpdatingLocation keep on giving me location. To stop this I can use [self.locationManager stopUpdatingLocation], but this look like a way out or hack.
Is there any better way to just get current location in iOS?
in your .h file
#import <CoreLocation/CoreLocation.h>
#interface LocationSearchViewController : UIViewController<UITextFieldDelegate,CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
}
in your .m file
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
[locationManager stopUpdatingLocation]; // when u got the lat and long it stop uoatde the location
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSString *getcurrlong = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
NSSting *getcurrlat = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
You can't think of location in those precise terms. You'll get back increasingly accurate locations from the location manager and it's up to you to decide when it's accurate enough. You have to weigh this against power usage and time. The location updates will never be completely accurate. The will never be returned immediately. The device has to power up hardware, then listen for GPS/WiFi/Cell signals and use all those to calculate location.
There's no way to ask for "my precise current location" and have it given to you immediately. Location is not a property like [NSDate date]. You can only ask for best-estimate location updates and they will only come to you in imprecise measurements, and never instantaneously (excepting cached location).
Check it
-(void)getCurrentLocation
{
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.delegate = self;
[locationManager startUpdatingLocation];
startLocation = nil;
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if (startLocation == nil)
{
startLocation = newLocation;
[locationManager setDelegate:nil];
locationManager = nil;
}
}
EDIT: Ok, I just have noticed that the problem is exclusive of iOS 7. I'm still being unable to solve it, however, so I suppouse I'll try with the sugestions bellow. Thanks to all!
¡Hi! I'm programming a navigator app, and I need to update the user position whenever is possible. I have two View Controllers that use CLLocation manager. In both of them I've added this line:
#import <CoreLocation/CoreLocation.h>
And then added the to the interface declaration, and I'm setting this as a property in the .h file, and synthetizing afterwards:
#property (strong, nonatomic) CLLocationManager *locationManager;
After that, I'm launching de locationManager in the viewDidLoad, this way:
if(self){
locationManager = [[CLLocationManager alloc] init];
//locationManager.delegate = self;
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLHeadingFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager startUpdatingLocation];
}
And here are my delegate methods.
For the first View:
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
homeLatitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude] doubleValue];
homeLongitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude] doubleValue];
NSLog(#"Updated! -> hl = %f, hlg = %f", homeLatitude, homeLongitude);
}
}
For the second view. As you can see, I replaced the old didUpdateToLocation with didUpdateLocations, as a desperate try.
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
/*- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSLog(#"Tarzan boy");
_testLabel.text = [NSString stringWithFormat:#"Oh DAMN!!!!"];
}
}*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(#"didUpdateToLocation: %#", [locations lastObject]);
CLLocation *currentLocation = [locations lastObject];
if (currentLocation != nil) {
currentLatitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude] doubleValue];
currentLongitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude] doubleValue];
NSLog(#"Updated! (MapWithRoutesViewController) -> hl = %f, hlg = %f", currentLatitude, currentLongitude);
_testLabel.text = [NSString stringWithFormat:#"Update! -> hl = %f, hlg = %f", currentLatitude, currentLongitude];
//Aquí es donde borramos el lugar al que llegaron.
if(mapView){
if(followMe){
CLLocationCoordinate2D *c = &((CLLocationCoordinate2D){.latitude = currentLatitude, .longitude = currentLongitude});
[mapView.mapView as_setCenterCoordinate:*c zoomLevel:32 animated:NO];
_ourStepper.value = [mapView.mapView as_zoomLevel];
}
if([mapView getNearestDestinyDistance:currentLocation] < 150.0){
NSLog(#"Hay que eliminar el primer destino del MapView");
mapView.destinoActual++;
}
if([mapView getNearestPointDistance:currentLocation] > 200.0){
NSLog(#"Hay que recalcular la ruta al destinoActual");
SpinnerView *spinner = [SpinnerView loadSpinnerIntoView:self.view];
spinner.tag = 98;
while (![mapView recalculateRoutesTo:currentLocation]) {
//do nothin...
}
[spinner removeSpinner];
}
}
}
//[locationManager stopUpdatingLocation];
}
As you can see, the line
//[locationManager stopUpdatingLocation];
is commented. Well, the problem is driving me crazy is that the code above works as a charm in the first view controller, and update periodically as I expected. But in the second view, it works only the first time, and never updates again. I programmed these methods in different times, so I can't remember if I did something to the first view I didn't to the second. But they are in the same app, so I assume there's no problem with libraries or permissions. Any help or hint is welcome, thanks!
First off, if you are doing navigation, you should be registering for significant change notifications. Go read the documentation on that here. It's much more efficient. You will have to turn it off when you are not using it, but it's much better. Support for it goes all the way back to iOS 4. That's 99% of the user population for sure.
I had a similar situation in my application and implemented a singleton that handles all location updates and then fires off NSNotificaitons to the foreground threads.
Create a singleton class that handles the location updates View would
register to listen to LOCATION_CHANGE updates perhaps Background
singleton object registers as the delegate for the location manager
This may not be the answer you are looking for but i know it worked in my case.
Found the solution here. The locationManager works when I launch it this way:
if(self){
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLHeadingFilterNone];
//change the desired accuracy to kCLLocationAccuracyBest
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//SOLUTION: set setPausesLocationUpdatesAutomatically to NO
[locationManager setPausesLocationUpdatesAutomatically:NO];
[locationManager startUpdatingLocation];
}
I'll work anyway in performance like Rob suggested. Thanks to all for the help!
I wrote an CLLocationManager ios app. However, I cannot see my app appears in the Location Services in the settings on my iPhone. Do I need to set a specific value in plist in my ios project in Xcode? Thanks in advance!
It should appear automatically once code that actually requires location tracking is being called (whenever the popup first show: do you allow...)
try calling something like this:
[self.locationManager startUpdatingLocation];
And that should do it
In iOS -8 need to do some changes :
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]){
[locationManager requestWhenInUseAuthorization];
}else{
[locationManager startUpdatingLocation];
}
need to add 2 extra key in plist with blank value
1)NSLocationWhenInUseUsageDescription
2)NSLocationAlwaysUsageDescription
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSString *strLat = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
NSString *strLong = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}