I have worked on one application name time tracker. User can manually swipe in and swipe out manually by clicking the button.
Now I would like to make it as automatic based on the location detection. For that I am using CLLocationManager class. It works fine sometimes and sometimes it gives wrong swipe details. I am using below code.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
_latitude.text = [NSString stringWithFormat:#"Latitude: %f", newLocation.coordinate.latitude];
_longitude.text = [NSString stringWithFormat:#"Longitude: %f", newLocation.coordinate.longitude];
if([_latitude.text doubleValue] > 17.76890) && [_longitude.text doubleValue] > 78.34567) {
if (isSwipeIn) {
isSwipeIn = false;
//necessary swipe out UI and logic
} else {
isSwipeIn = true;
//necessary swipe in UI and logic
}
}
}
Can anyone help me on this..
Instead of comparing lat-long, go for a range check like if your device is within few meter mark as swipe in otherwise swipe out.
You can check distance between two lat-long using following method in Objective-C
CLLocation *location; // Your Location to compare
CLLocation *currentLocation; // Your current location
double distance = [location distanceFromLocation:currentLocation]; // Returns distance in meters
// Now lets say you are within 5 meters mark Swipe In
if(distance <= 5)
// Mark swipe IN
else
// Mark swipe OUT
I hope this will help you. Happy coding :)
There is another way to do this, you can get distance from target location and check it with horizontalAccuracy of current location.
The delta gives you the distance between current location and targeted location. If delta is less than (<) horizontalAccuracy than current location is in a circle with a radius of horizontalAccuracy.
If delta is greater than (>) horizontalAccuracy than current location is far away than your targeted location.
So now CLLocationManager delegate method will be looks like below:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
_latitude.text = [NSString stringWithFormat:#"Latitude: %f", newLocation.coordinate.latitude];
_longitude.text = [NSString stringWithFormat:#"Longitude: %f", newLocation.coordinate.longitude];
// Create Location object for your target location. e.g. (17.76890,78.34567)
CLLocation *targetLocation = [[CLLocation alloc] initWithLatitude:17.76890 longitude:78.34567];
CLLocationDistance delta = [newLocation distanceFromLocation:targetLocation];
if (delta > newLocation.horizontalAccuracy) {
if (isSwipeIn) {
isSwipeIn = false;
//necessary swipe out UI and logic
} else {
isSwipeIn = true;
//necessary swipe in UI and logic
}
}
}
Related
My code is for a Golf player app. I need the exact user location here is my present code
- (void) update_location
{
locationManager_player = [[CLLocationManager alloc] init];
locationManager_player.delegate = self;
locationManager_player.desiredAccuracy = kCLLocationAccuracyBest;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
[locationManager_player requestWhenInUseAuthorization];
}
[locationManager_player startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// Code to handle the current user location
}
The above delegate method is not giving the exact user location. Perhaps this gives the coordinates which are 30 to 40 yards far from user current position
Thanks in advance
Location accuracy is controlled by the desiredAccuracy property of CLLocationManager. Check what is set in your case. Default value is kCLLocationAccuracyBest. You can set it to kCLLocationAccuracyBestForNavigation but it require more power requirements.
More detail here.
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;
}
I'm trying to implement a function of a Geo location for a user, I'm statically setting up latitude and longitude information, when app starts if the user is within that area I'm showing up a message that "You've been reached to office" else "You're going out from office". I've implemented below code to achieve this, I tried by moving all around by steps and on vehicles, but in both the cases it always shows that "You've been reached to office", however I was 2km away from that location! I think the problem is in the comparison of Geo data in CLLocationManager delegate.
- (void) startUpdateUserLocation
{
if(!locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
// [locationManager startUpdatingLocation];
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(latitude, longitude);
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:coord radius:kCLDistanceFilterNone identifier:#"identifier"];
[locationManager startMonitoringForRegion:region];
}
- (void)viewDidLoad
{
[super viewDidLoad];
latitude = 23.076289;
longitude = 72.508129;
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
MKCoordinateRegion region;
region.center = mapView.userLocation.coordinate;
region.span = MKCoordinateSpanMake(0.25, 0.25);
region = [mapView regionThatFits:region];
[mapView setRegion:region animated:YES];
lblCurrentCoords.text = [NSString stringWithFormat:#"lat %f lon %f",mapView.userLocation.coordinate.latitude,mapView.userLocation.coordinate.longitude];
[self startUpdateUserLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didEnterRegion:(CLRegion *)region __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0)
{
[listOfPoints addObject:manager.location];
[tablePoints reloadData];
/*
* locationManager:didEnterRegion:
*
* Discussion:
* Invoked when the user enters a monitored region. This callback will be invoked for every allocated
* CLLocationManager instance with a non-nil delegate that implements this method.
*/
lblLocationStatus.text = #"You're in office area!...";
}
- (void)locationManager:(CLLocationManager *)manager
didExitRegion:(CLRegion *)region __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0)
{
/*
* locationManager:didExitRegion:
*
* Discussion:
* Invoked when the user exits a monitored region. This callback will be invoked for every allocated
* CLLocationManager instance with a non-nil delegate that implements this method.
*/
lblLocationStatus.text = #"You're going out from office area!...";
}
- (void)locationManager:(CLLocationManager *)manager
didStartMonitoringForRegion:(CLRegion *)region __OSX_AVAILABLE_STARTING(__MAC_TBD,__IPHONE_5_0)
{
/*
* locationManager:didStartMonitoringForRegion:
*
* Discussion:
* Invoked when a monitoring for a region started successfully.
*/
lblLocationStatus.text = #"Start monitoring...";
}
- (void)locationManager:(CLLocationManager *)manager
monitoringDidFailForRegion:(CLRegion *)region
withError:(NSError *)error __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0)
{
/*
* locationManager:monitoringDidFailForRegion:withError:
*
* Discussion:
* Invoked when a region monitoring error has occurred. Error types are defined in "CLError.h".
*/
lblLocationStatus.text = #"Stop monitoring...";
}
I am trying to accomplish the following things!
If the user entered into the Geo location, he should be "alert". --- How to match location?
If moving around within that Geo location then the code should be monitoring this activity! --- Need to set a desired accuracy property?
I want my code to check constantly for the user Geo location, how do I do that? --- Need to call function in NSTimer ?
I found many questions on SO asked about the same but NO one has matched answers! Someone please guide me whether I'm going in the right direction or not as this code doesn't show up! :)
It sounds like you should be using region monitoring instead, which tells you when the user enters or exits a circular area. Set it up with startMonitoringForRegion: and implement the CLLocationManagerDelegate methods
– locationManager:didEnterRegion:
– locationManager:didExitRegion:
– locationManager:monitoringDidFailForRegion:withError:
– locationManager:didStartMonitoringForRegion:
If you're having trouble with bad location data coming in, check for the age of the CLLocation in locationManager:didUpdateLocations: or locationManager:didUpdateToLocation:fromLocation:. If it's more than 60 seconds old, don't use it.
I have a MKMapView on my app. This is iOS6.
-(void)viewDidLoad
{
.....
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"Update locations is hit");
NSLog(#"379 the locations count is %d",locations.count);
CLLocation *obj = [locations lastObject];
NSLog(#"the lat is %f", obj.coordinate.latitude);
NSLog(#"the long is %f", obj.coordinate.longitude);
NSLog(#"the horizontal accuracy is %f",obj.horizontalAccuracy);
NSLog(#"the vertical accuracty is %f",obj.verticalAccuracy);
if (obj.coordinate.latitude != 0 && obj.coordinate.longitude != 0)
{
CLLocationCoordinate2D currrentCoordinates ;
currrentCoordinates.latitude = obj.coordinate.latitude;
currrentCoordinates.longitude = obj.coordinate.longitude;
}
....more computation
[locationManager stopUpdatingLocation];
}
When I first load the app, my location is showing little far away. Some times miles away. I also have a reset location button and if I click that map shows correct location. This is what I have in reset location button click:
- (IBAction)btnResetLocationClick:(UIButton *)sender
{
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager startUpdatingLocation];
}
So how do I make the app get the correct current location on load up itself. Is there a way for the app to tell the map to wait for few milliseconds and then update. Or any other idea? Please let me know. If you need more information, please ask. Thanks.
What you could do is to:
do not turn off location services in didUpdateLocations automatically, but rather;
turn off location services in didUpdateLocations only if you're sufficiently happy with the horizontalAccuracy; and
even if you don't get the desired accuracy, turn off location services after a certain amount of time has passed.
Thus, didUpdateLocations might look like:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
// do whatever you want with the location
// finally turn off location services if we're close enough
//
// I'm using 100m; maybe that's too far for you, but 5m is probably too small
// as you frequently never get that accurate of a location
if (location.horizontalAccuracy > 0 && location.horizontalAccuracy < 100)
[locationManager stopUpdatingLocation];
}
And then in viewDidLoad, turn if off after a certain period of time has passed (you might want to check some status variable that you set if you've already turned off location services):
-(void)viewDidLoad
{
.....
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager startUpdatingLocation];
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 60.0 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[locationManager stopUpdatingLocation];
});
}
Original answer:
I don't see where you're updating your map to be around your location. I'd expect to see something like:
self.mapView.centerCoordinate = location.coordinate;
or like:
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(location.coordinate, 300, 300);
[self.mapView setRegion:region];
I'd also suggest, rather than turning off location services immediately (since frequently the first few locations are not that accurate), leave it on for a bit and let it hone in on your location until the horizontalAccuracy and verticalAccuracy fall within a certain predetermined limit. Look at those accuracy figures for a few calls to didUpdateLocations and you'll see what I mean.
I originally thought you were getting a negative horizontalAccuracy at which point I suggested implementing didFailToLocateUserWithError because according to horizontalAccuracy, "A negative value indicates that the location’s latitude and longitude are invalid." Hopefully you get an error that describes what the issue is. Even if you're not currently getting a negative horizontalAccuracy, you might want to implement this method, just to make sure you're handling any errors correctly.
You can't make the GPS in the iPhone more accurate in your app, but you can check that the result is accurate before carrying on. Right now you're only checking the lat and long aren't 0, but if you check obj's horizontalAccuracy then you'll know when the location information is good enough. Don't stopUpdatingLoation until that happens.
I'm in the process of writing an application that shows the user's distance from a fixed point as the user walks around (i.e. the label showing the distance from the user to the point is updated every time the user moves). I use a CLLocationManager with the code shown below:
- (void)viewDidLoad
{
locationManager=[[CLLocationManager alloc]init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocationDistance meters = [newLocation distanceFromLocation:fixedPoint];
self.distanceLabel.text = [[NSString alloc] initWithFormat:#"Distance: %.1f feet", meters*3.2808399];
}
The label that is supposed to show the distance from the user to the point isn't updated constantly and when it is updated, it doesn't usually show the correct distance from the user to the fixed point. I was wondering if there is a better way for me to try and do this, or do the fundamental limitations of the core location framework make this impossible. Any help will be greatly appreciated.
Are you filtering out old (cached) positions? You should also filter based on accuracy, you probably don't want low accuracy locations.
You won't get continous or periodic update, the callback only occurs when the location has changed.
Assuming the device has GPS and can see enough GPS satellites to get a good position, this works fine.
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSTimeInterval age = -[newLocation.timestamp timeIntervalSinceNow];
if (age > 120) return; // ignore old (cached) updates
if (newLocation.horizontalAccuracy < 0) return; // ignore invalid udpates
...
}