iOS Geolocation Not Updating - ios

Using iOS 8 and have NSLocationAlwaysUsageDescription set.
Here is my code:
#import "GeoLocation.h"
#import "AppDelegate.h"
#implementation GeoLocation
- (id)init
{
self = [super init];
if (self)
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 5; //in meters
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
self.numberOfUpdates = 0;
[self.locationManager startUpdatingLocation];
}
return self;
}
// Wait for location callbacks
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"Location Updated: %#", [locations lastObject]);
}
- (float) getLatitude
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSLog(#"getLatitude: %f", self.locationManager.location.coordinate.latitude);
appDelegate.gMyProfile.latitude = self.locationManager.location.coordinate.latitude;
return self.locationManager.location.coordinate.latitude;
}
- (float) getLongitude
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSLog(#"getLongitude: %f", self.locationManager.location.coordinate.longitude);
appDelegate.gMyProfile.longitude = self.locationManager.location.coordinate.longitude;
return self.locationManager.location.coordinate.longitude;
}
- (float) getAltitude
{
return self.locationManager.location.altitude;
}
When the user logs in, I instantiate a GeoLocation object, which turn on starts updating the location.
If I use
self.locationManager.distanceFilter = 5;
and walk around my house, didUpdateLocations won't fire.
However, if I get rid of
self.locationManager.distanceFilter = 5;
didUpdateLocations will fire every second.
Anything you guys see that I am not. I would love for this to update when the user moves 5 meters.

Adding a distance filter will most likely cause iOS to take the horizontalAccuracy into account.
Since you are inside you will be unlikely to get location with a horizontalAccuracy of 5 which is the best accuracy.
Without the distance filter you are probably just getting the same location or another location within the distance in horizontalAccuracy.
Generally you will only get an accuracy of 5m meters when you are outside in clear view of the satellites above you and not next to tall buildings that can reflect and obscure the signal.

Related

Getting Current Location instead of Cache ios

I have searched a lot and didn't get any satisfactory answer, I have a scenario where I am showing a list of sellers based on user's current location. I am getting a location for the first time and when I run my App afterward whenever I try to get the location I am getting a cache location data. I did try after some time even after every 24 hours but still getting the cache location where my current location is changed as well. Following is the code I am using for reference. please advise.
Property defined in Header file
#property (nonatomic,retain) CLLocationManager *locationManager;
- (void)startSingleLocationRequest
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[self.locationManager startUpdatingLocation];
[self.locationManager requestWhenInUseAuthorization];
}
#pragma mark --didUpdateLocations
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
self.latitudeValue = locations.lastObject.coordinate.latitude;
self.longitudeValue = locations.lastObject.coordinate.longitude;
// location set for simulation to UK
if(self.latitudeValue != 51.509979 && self.longitudeValue != -0.133700){
[MBProgressHUD hideHUDForView:self.outletSearchNearBy animated:YES];
[self.locationManager stopUpdatingLocation];
abc *slv =[self.storyboard instantiateViewControllerWithIdentifier:#"abc"];
slv.receivedLatitudeValue = self.latitudeValue;
slv.receivedLongitudeValue = self.longitudeValue;
[self.navigationController pushViewController:slv animated:YES];
}
else{}
}
You can do something like,
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
for(int i=0;i<locations.count;i++){
CLLocation * newLocation = [locations objectAtIndex:i];
CLLocationCoordinate2D theLocation = newLocation.coordinate;
CLLocationAccuracy theAccuracy = newLocation.horizontalAccuracy;
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0)
{
continue;
}
// do your all stuff here and then
break;
}
}
Your code will not executes if your location age is more than 5 seconds. You can decide location age lie 10 seconds or 20 seconds!
Update :
Just replace your property declaration
#property (nonatomic,retain) CLLocationManager *locationManager;
with
#property (nonatomic,strong) CLLocationManager *locationManager;
or
just declare it as instance variable like,
CLLocationManager *locationManager;
and remove self from avery instance of it!
Second thing,
You should do first,
[self.locationManager requestWhenInUseAuthorization];
and then start update of location,
[self.locationManager startUpdatingLocation];
Can you try like this
self.locationManager.pausesLocationUpdatesAutomatically = NO;
Because it
Specifies that location updates may automatically be paused when possible.
By default, this is YES for applications linked against iOS 6.0 or later.
On the other hand, kCLLocationAccuracyBestForNavigation uses top speed GPS. So better to use this instead of kCLLocationAccuracyNearestTenMeters.
Lion thanks for the support, actually i was checking location inside the plaza and due to that i was not getting the right location, i tested by coming outside and it is showing perfectly. anyways thanks lion you have been really helpful.

AFNetworking and CLLocation Manager iOS

My question is as follows:
When is the location updated when using Location Services? When I called startUpdatingLocation I expected to already have a location returned so I can retrieve latitude and longitude for my iOS project. These are required parameters for a web service as well but it seems they are returned as nil.
The interface conforms to CLLocationManagerDelegate protocol and I have implemented the methods for it. Anyway here is my code:
- (void)viewDidLoad
{
super viewDidLoad];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
if([self.parentViewController isKindOfClass:[BTMainViewController class]])
{
BTMainViewController *parent = (BTMainViewController *)self.parentViewController;
self.sessionKey = parent.session;
NSLog(#"URL is %# ", self.sessionKey);
}
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// also set the URL
self.serviceURL = [apiURL stringByAppendingString:#"/get_employee_closestlocations"];
// set tableview delegate and data source
self.tableView.delegate = self;
self.tableView.dataSource = self;
// adjust for EdgeInset with navigation bar.
self.tableView.contentInset = UIEdgeInsetsMake(64.0f, 0.0f, 0.0f, 0.0f);
// fetch the locations here
[locationManager startUpdatingLocation];
[self fetchLocations];
}
didUpdateToLocation implementation
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = [locationManager location];
[locationManager stopUpdatingLocation];
if(currentLocation != nil)
{
[self setLongitude:[NSNumber numberWithDouble: currentLocation.coordinate.longitude]];
[self setLatitude:[NSNumber numberWithDouble: currentLocation.coordinate.latitude]];
}
}
Any suggestions would be welcome and thanks in advance!
The delegate method you are using is deprecated. You should use locationManager:didUpdateLocations: and then access the location update from the end of the array -
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *currentLocation = (CLLocation *)[locations lastObject];
...
}
It can take some time to get a location fix, particularly as you have specified kCLLocationAccuracyBest - iOS may need to start up the GPS receiver if it hasn't been used recently and then the GPS needs to obtain a fix - if the device is inside or has bad GPS reception this can further delay the acquisition of a location. You can get an idea of the time to obtain a fix by restarting your device, starting the maps application and tapping the location "arrow" and waiting until the blue location circle collapses down to the blue & white marker.
I would suggest that you invoke your [self fetchLocations]; from the didUpdateLocations method
Also, the Core Location documentation states -
When requesting high-accuracy location data, the initial event
delivered by the location service may not have the accuracy you
requested. The location service delivers the initial event as quickly
as possible. It then continues to determine the location with the
accuracy you requested and delivers additional events, as necessary,
when that data is available.
So, there is a risk that when you do access the location, it may not be particularly accurate. You can look at the horizontalAccuracy property of the CLLocation and decide whether you want to accept this location or wait for a more accurate location (bearing in mind that it may not arrive if the device is inside or has poor reception)
You need to do in viewDidLoad like this
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
mapView.delegate = self;
mapView.showsUserLocation = YES; // Enable it when we want to track user's current location.
}
after doing this the below delegate method will automatically called.
- (void)mapView:(MKMapView *)mapView
didUpdateUserLocation:
(MKUserLocation *)userLocation
{
self.mapView.centerCoordinate = userLocation.location.coordinate;
}

iOS 7 Simulator on Mac doesn't work with custom location (Also doesn't ask permission)

I'm trying to make an iOS7 app that uses the current location of the device. I'm using the iPhone simulator on my Mac, but I'm having some problems. Every time my view that the location manager is in appears, it prints out 0.000000 for both latitude and longitude, even after I've set a custom location (from simulator>debug>location).
Also, it seemed strange that the simulator didn't ask for permission to use current location when it opened the app. Anybody know what's going on here?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
_location = [locationManager location];
_coord.longitude = _location.coordinate.longitude;
_coord.latitude = _location.coordinate.latitude;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
_coord.longitude = _location.coordinate.longitude;
_coord.latitude = _location.coordinate.latitude;
printf("%f\n",self.coord.longitude);
printf("%f\n",self.coord.latitude);
}
You need to get the newLocation from the delegate method didUpdateLocationToLocation:fromLocation:. Also implement didFailWithError delegate method. It takes some time before you start getting updated locations, hence the delegate call.
The last location is usually cached, so it maybe wise to check location's timestamp and filter the old location out.
Edit:
This is the cleanest example I can provide. Start new project in Xcode, pick Single View application template, iPhone. Don't touch storyboard, just replace content of your ViewController.m with this and run in Simulator or device. If on Simulator, go to Debug and set some location and you will get coordinates in the console. I am also starting and stopping location updates when the view goes on or off screen.
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#implementation ViewController
#pragma mark - Location Manager delegate methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ([newLocation.timestamp timeIntervalSinceNow] >= -300.0) {
NSLog(#"updated location with latitude %f longitude %f", newLocation.coordinate.longitude, newLocation.coordinate.latitude);
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.locationManager startUpdatingLocation];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.locationManager stopUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if(error.code == kCLErrorDenied) {
// alert user
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Access to location services is disabled"
message:#"You can turn Location Services on in Settings -> Privacy -> Location Services"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if(error.code == kCLErrorLocationUnknown) {
NSLog(#"Error: location unknown");
} else {
NSLog(#"Error retrieving location");
}
}
#pragma mark - Location Manager getter
- (CLLocationManager *)locationManager
{
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
_locationManager.distanceFilter = 60.0;
}
return _locationManager;
}
#end

Best technique for counting laps?

I'm making an app that needs to count laps for participants walking around a track. I thought that I could create a small geo-fence around the start point and have the OS let me know when the user entered it, however this doesn't seem to work as well as I was hoping. It seems that it isn't triggered reliably when the walker enters the fence or triggers in other areas around the track. (I'm testing without letting the device go to sleep at this time).
It also seems that the locationManager:didExitRegion method isn't called properly in my testing.
When the user taps the start button, the following method is called:
-(void)startLocationManager {
if ([CLLocationManager locationServicesEnabled] && usingLocationManager) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLLocationAccuracyBest;
self.locationManager.activityType = CLActivityTypeFitness;
[self.locationManager startUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *lastLocation = [locations lastObject];
if (lastLocation.horizontalAccuracy > 10) {
return;
}
// setup a geocode fence and count as user enters fence
self.startRegion = [[CLCircularRegion alloc] initWithCenter:lastLocation.coordinate radius:10 identifier:#"startPosition"];
[self.locationManager stopUpdatingLocation];
[self.locationManager startMonitoringForRegion:self.startRegion];
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
lapCount++;
[self updateLapDisplay];
}
Am I doing something wrong or can I not use CoreLocation in such a fashion?
A geofence won't work well for this. You can't rely on it to trigger accurately or reliably. Use a location manager and its delegate in the normal way and trigger manually when the user comes to within 10 or 20 meters, then reset the trigger when they're 50 or 100 meters away from it.

location manager giving null coordinates

The following code results in null coordinates. The weird thing is the UIAlert prompting the app to use current location appears briefly before the user can select yes.
My code which i have used :
CLLocationManager *locationManager;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
float latitude = locationManager.location.coordinate.latitude;
float longitude = locationManager.location.coordinate.longitude;
NSLog(#"%.8f",latitude);
NSLog(#"%.8f",longitude);
The NSLog prints 0.0000000 for both coordinates.
Thanks!
The reason you're getting 0 is because the location manager hasn't collected any data at that point (it has started thought)
You need to set your class as the delegate of the location manager (ie supplying a function that is called whenever a new location is retrieved), and also retain your location manager.
// Inside .m file
#interface MyClass () <CLLocationManagerDelegate> // Declare this class to implement protocol CLLocationManagerDelegate
#property (strong, nonatomic) CLLocationManager* locationManager; // Retains it with strong keyword
#end
#implementation MyClass
// Inside some method
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[self.locationManager startUpdatingLocation];
// Delegate method
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation* loc = [locations lastObject]; // locations is guaranteed to have at least one object
float latitude = loc.coordinate.latitude;
float longitude = loc.coordinate.longitude;
NSLog(#"%.8f",latitude);
NSLog(#"%.8f",longitude);
}

Resources