In my app there's a button to add records to DataBase. Every time user tap that button, he adds a record to the DB. Part of that record should be the location of the user when he tapped the button.
So, in my code, when button is tapped, I invoke a method which track the user position. Trouble is that iPhone can't find immediately user's position so record is saved without coordinates (if I create another record around 10 seconds later everything works correctly).
Is there a way to track user only when he pushes the button and adding coordinates when available?
#property(nonatomic,strong) CLLocationManager *locationManager;
in ViewDidLoad
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate=self;
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)])
{
[self.locationManager requestAlwaysAuthorization];
}
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
Then
-(IBAction)button_Clicked:(id)sender
{
[self.locationManager startUpdatingLocation];
}
#pragma mark - Location Manager delegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations
{
CLLocation *location = [locations firstObject];
CLLocationCoordinate2D coordinate = location.coordinate;
}
Related
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.
I'm trying to getting my current location exact according to my coordinates. I've implemented CLLocationManager in my viewController called myLocation.
My problem is, I'm getting not getting my co-ordinates for the first time, but when I again approach I got the coordinates. I'm unable to understand this problem that why this not appear for the first time.
I also tried to give a NSTimer to stoplocation but but still unable to get the result for the first time, every first time I getting a (null) value, and then getting the co-ordinates.
My Code:
#import <UIKit/UIKit.h>
#import <Corelocation/CoreLocation.h>
#interface myLocation : UITableViewController<CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#interface myLocation () {
CLLocationManager* _locationManager;
NSString * _lat;
NSString * _lng;
}
#end
#implementation myLocation
- (void)viewDidLoad
{
[super viewDidLoad];
_locationManager = [[CLLocationManager alloc] init];
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
[_locationManager requestWhenInUseAuthorization];
[_locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
[_locationManager stopUpdatingLocation];
_lat =[NSString stringWithFormat:#"%f",location.coordinate.latitude];
_lng =[NSString stringWithFormat:#"%f",location.coordinate.longitude];
}
- (void)viewWillAppear:(BOOL) animated
{
NSLOG(#"%#",_lat);
NSLOG(#"%#",_lng);
}
Your coordinates aren't appearing yet when you attempt to print them in viewWillAppear: because the CLLocationManager hasn't had enough time to retrieve the first location yet. Wait until didUpdateLocations: is first called before attempting to utilize the device coordinates because didUpdateLocations: is where you'll be receiving those coordinates. I recommend deleting your attempt to print the coordinates code from your viewWillAppear and simply print them in didUpdateLocations: instead.
In the comments, the OP stated he wants to "refresh" the location during viewWillAppear. I suggest stopping the updates when the view disappears and restarting the updates as soon as the view reappears:
- (void)viewWillAppear:(BOOL) animated
{
[_locationManager startUpdatingLocation];
}
- (void)viewWillDisappear:(BOOL) animated
{
[_locationManager stopUpdatingLocation];
}
It takes some time for location services to start up and call your delegate method - This almost certainly won't happen before viewWillAppear is called if you are only starting location services in viewDidLoad. Also, the first time your app executes it has to wait for the user to grant permission.
You can examine the location property of your CLLocationManager to get the most recent location. If it is nil then no location has been determined (yet).
I have IBAction:
-(IBAction)pressStart{
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
In
- (void)viewDidLoad
{
[super viewDidLoad];
duration.text = #"00:00:00";
speedLabel.text = #"00";
locationManager = [[CLLocationManager alloc]init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
}
And this method:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *firstLocation = [locations objectAtIndex:0];
location = [locations lastObject];
CLLocationDistance meters = [location distanceFromLocation:firstLocation];
NSLog(#"meters= %f", meters);
And I don't know why the firstLocation is changing. Maybe there is a way to capture firstLocation? This should be the location of the device when the button Start is pressed.
firstLocation in your code is not the first location since location updates started; it is the first location to be returned to you since the previous callback to the locationManager:didUpdateLocations: method (the location services may collect multiple locations before calling back to your delegate method in certain circumstances -- the most recent location is always going to be the last object in the locations array).
If you need to store the first location since location updates started, you should create a property such as
#property (nonatomic, strong) CLLocation *startingLocation;
Then in the locationManager:didUpdateLocations: method, add the code:
if (!self.startingLocation) {
self.startingLocation = [locations objectAtIndex:0];
}
That will store the starting location into the property after the first callback. (You can set the property to nil if you want to reset it.)
Don't forget that the very first location you receive many not be very accurate, as it takes time for location services to get a fix on the device's position if they were not recently enabled.
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.
Hi I am implementing Location services in my app. First I have to know my Coordinates to get the distance between some places that I have in a list and the device. Then if I go into a place I can make a check in, so, I need to get coordinates again, and the problem is here. Second time I try to get coordinates, the method -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations is not called.. and I can not get new Coordinates.
My manager is located in a NSObject sublcass with this code:
(id)init {
if ( self = [super init] ) {
if ([CLLocationManager locationServicesEnabled])
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
}
return self;
}
-(void) checkLongLatitudeAgain {
[locationManager startUpdatingLocation];
}
#pragma mark Delegates de CLLocationManager
//
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
NSLog(#"LON%f", manager.location.coordinate.longitude);
NSLog(#"LAT:%f", manager.location.coordinate.latitude);
NSTimeInterval howRecentNewLocation = [newLocationeventDate timeIntervalSinceNow];
if (manager.location.horizontalAccuracy <= 100.0 && howRecentNewLocation < -0.0 && howRecentNewLocation > -20.0){
//Usar coordenada
[self.delegate getLocationForCheckIn:manager.location];
[self stopUpdatingLocation:#"Fins"];
}
}
// ---------------------------------------------------------------------------------------------------------------------
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
//
if ([error code] != kCLErrorLocationUnknown) {
[self stopUpdatingLocation:NSLocalizedString(#"Error", #"Error")];
}
//
}
// ---------------------------------------------------------------------------------------------------------------------
- (void)stopUpdatingLocation:(NSString *)state {
//Detenemos la lectura del GPS
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
NSLog(#"Stop gps");
//
}
I call the class when the list of places is open, and also when inside a place the user press checkIn button. Both times I do it with this code:
WPLocationManager *location = [[WPLocationManager alloc]init];
[location checkLongLatitudeAgain];
You are creating a new manager every time:
WPLocationManager *location = [[WPLocationManager alloc]init];
[location checkLongLatitudeAgain];
That new manager is not assigned to any delegate.
You need to use the previous manager you have created and assigned to your delegate, something like:
[locationManager checkLongLatitudeAgain];
You can check the documentation at http://developer.apple.com - https://developer.apple.com/library/ios/documentation/userexperience/conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html
In particular you can check the Starting the Standard Location Service and Starting the Significant-Change Location Service sections. You have to use the startMonitoringSignificantLocationChanges or startUpdatingLocation method of CLLocationManager, cache your location somewhere and update it only when a new location is received, otherwise like it is stated in the documentation: "If a location update has already been delivered, you can also get the most recent location data directly from the CLLocationManager object without waiting for a new event to be delivered".
i dont know why you are initiating your location manager again again, also even if you some how manage to solve current problem but it's not proper way of dealing with location manage based applications.I had been in trouble previously when i was working on location based app. the best approach for location based app is singleton.
apple forum discussion
you can find
this
and this very helpful.
just an advice, :)
Thanks.
In iOS8 for me I had to call [locationManager stopUpdatingLocation]; before calling [locationManager startUpdatingLocation] to start getting updates second time and it works for me.