Calculating Distance between two coordinates using CLLocation - ios

I'm using CLLocationDistance to get the distance between two points, but I'm getting an error when passing my current location in it.
CLLocation *current = [[CLLocation alloc] initWithLatitude:startLocation.coordinate.latitude longitude:startLocation.coordinate.longitude];
CLLocation *itemLoc = [[CLLocation alloc] initWithLatitude:[[[getName objectAtIndex:indexPath.row] objectForKey:#"lat"] doubleValue] longitude:[[[getName objectAtIndex:indexPath.row] objectForKey:#"lon"] doubleValue]];
//Here the current location gives me an error "Initializing cllocation with an expression incompatible format"
CLLocationDistance *itemDist = [itemLoc distanceFromLocation:current];
NSLog(#"Distance: %#", itemDist);

The error you're getting is actually:
Initializing 'CLLocationDistance *' (aka 'double *') with an expression of incompatible type 'CLLocationDistance' (aka 'double')
What it's saying is you're initializing itemDist (which you've declared as a CLLocationDistance *) to something that is returning a CLLocationDistance (notice no asterisk).
CLLocationDistance is not an object.
It is just a primitive type (specifically double -- see the Core Location Data Types Reference).
So instead of declaring itemDist as a pointer to a CLLocationDistance, just declare it as a CLLocationDistance (no asterisk):
CLLocationDistance itemDist = [itemLoc distanceFromLocation:current];
You'll also need to update the NSLog to expect a double instead of an object otherwise it will crash at run-time:
NSLog(#"Distance: %f", itemDist);

Is swift 2.0 is in the following way:
let userLocation:CLLocation = CLLocation(latitude: 11.11, longitude: 22.22)
let priceLocation:CLLocation = CLLocation(latitude: 33.33, longitude: 44.44)
let meters:CLLocationDistance = userLocation.distanceFromLocation(priceLocation)

Below code will work for you
in view load
//************************** GEtting USer's latitude/ Longitude ********************
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
//************************** GEtting USer's latitude/ Longitude ********************
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) {
CLLocation *locA = [[CLLocation alloc] initWithLatitude:currentLocation.coordinate.longitude longitude:currentLocation.coordinate.latitude];
CLLocation *locB = [[CLLocation alloc] initWithLatitude:11.111111111111111 longitude:11.1111111111111111];
User_Vanue_Distance = [locA distanceFromLocation:locB];
NSLog(#"THIS IS THE DISTANCE BT TWO POINTS +++++++++++++++++++++%f",User_Vanue_Distance);
}
}
You need to put below keys in info.plist, in ios 8 to access location we need to put below keys in info.plist
1. NSLocationWhenInUseUsageDescription : Location required
2. NSLocationAlwaysUsageDescription Needed : Location Needed
This will work for you but one thing you need to add is add a check for ios8. otherwise this will crash on ios 7
// 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];
}
Hope this will work for you. :)

To find distance in KM from two different Lat & Long
let userLocation:CLLocation = CLLocation(latitude: 23.0320, longitude: 72.5250)
let priceLocation:CLLocation = CLLocation(latitude: 23.0283, longitude: 72.5067)
let distance = String(format: "%.2f km", userLocation.distanceFromLocation(priceLocation)/1000)
print("Distance is KM is:: \(distance)")

Related

Core Location can't get data in viewDidLoad

I wrote a simple iOS application that retrieves location information and then uses the location to request Yahoo Weather.
The problem is that even when I call the Core Location in the viewDidLoad, it won't give me the result immediately.
So why can't I get the location information?
How can I get the location information in viewDidLoad?
The pseudocode currently is something like:
- (void)viewDidLoad
{
[super viewDidLoad];
self.locManager = [[CLLocationManager alloc] init];
self.locManager.delegate = self;
self.locManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locManager.distanceFilter = 100;
[self.locManager startUpdatingLocation];
//won't get the current location right now, so the output will be null
NSLog(#"Current Location Longitude: %#", self.longitudeString);
NSLog(#"Current Location Latitude: %#", self.latitudeString);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
self.longitudeString = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
self.latitudeString = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
Location updates are not provided as instantly as you are expecting, you need to wait few seconds (2-3 or may be more) to get precise location update. If you want to have location data in viewDidLoad then you should init your location manager (and call startUpdatingLocation) before invoking the ViewController (since then it is not guaranteed that you will have location-data in viewDidLoad).

Altitude is always zero on iPhone simulator

I'm trying to develop an Altimeter on Xcode and Simulator but it always return 0 for the height above the sea.
I don't understand why, I've tried with a lot of places on Simulator.
My code is this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_mapView.delegate = self;
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.pausesLocationUpdatesAutomatically = YES;
_locationManager.delegate = self;
firstLocation = YES;
checkUserLocation = NO;
}
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
CLLocation *location = [locations lastObject];
lastLocation = location.coordinate;
_latitudeLabel.text = [NSString stringWithFormat:#"Current latitude: %f", location.coordinate.latitude];
_longitudeLabel.text = [NSString stringWithFormat:#"Current longitude: %f", location.coordinate.longitude];
_altitudeLabel.text = [NSString stringWithFormat:#"Current altitude: %f m", location.altitude];
}
Where is my error?
There's nothing wrong with your code, its because you are using the simulator.
Determining altitude requires a device with GPS capabilities, and you also need to be using GPS on that device in order to get it (wifi only location would not report altitude correctly even on GPS-enabled devices). The iOS simulator does not have those capabilities so altitude will not be accurate there. You will need to use a real device with GPS to get altitude measurements.
If you want to simulate a CLLocation with altitude you can create your CLLocation object and pass it an altitude yourself:
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
altitude:(CLLocationDistance)altitude
horizontalAccuracy:(CLLocationAccuracy)hAccuracy
verticalAccuracy:(CLLocationAccuracy)vAccuracy
timestamp:(NSDate *)timestamp
Altitude is a readonly property so you will need to create a new CLLocation object yourself instead of changing it manually when you receive a CLLocation object in your delegate callback.

startMonitoringForRegion is not sending to didEnterRegion or didExitRegion

I have a location based app, all though the region is correct the app never moves to didEnterRegion or didExitRegion
for (int x = 0; x <= [[[TaskStore sharedStore] allTasks]count]-1; x++)
{
NSArray *tasks = [[TaskStore sharedStore] allTasks];
Task *selectedTask = [tasks objectAtIndex:x];
location.latitude = selectedTask.locationCoord.coordinate.latitude;
location.longitude = selectedTask.locationCoord.coordinate.longitude;
NSString* desiriedLoc = [selectedTask locationName];
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter: location radius: 30.0 identifier: desiriedLoc];
NSLog(#"Entered new Location in Region %#", region);
[locManager startMonitoringForRegion:region];
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(#"didEnterRegion for %#",region.identifier);
UIAlertView *alr=[[UIAlertView alloc] initWithTitle:#"Reminder didEnterRegion"
message:region.identifier delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Ok",nil];
[alr show];
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"didExitRegion for %#",region.identifier);
UIAlertView *alr=[[UIAlertView alloc] initWithTitle:#"Reminder didExitRegion" message:region.identifier delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Ok",nil];
[alr show];
}
Here is a string print out from my location:
Entered new Location with the coordinates Latitude: 51.509980 Longitude: -0.133700
and here is a string print out from the region:
Entered new Location in Region (identifier London) <+51.50998000,-0.13370000> radius 30.00m
As #verbumdei commented, the only way you will get the -didEnterRegion and -didExitRegion is to establish a CLLocationManagerDelegate. Set your view as the delegate and add those methods and you should see the update.
One thing to note, you are using a 30M radius, you will need to be quite approximate in your location if you want to trigger updates. This is fairly easy to do in the Simulator, but in real life usage (on device), 30M accuracy is a bit tougher. I would start with 100M and work your way down based on experience.
If you start monitoring while staying in the target region, nothing triggered.
Because it's not really an "didEnterRegion" event.
You don't seem to be setting
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
Without explicitly setting these properties, the specified events will not get fired.

CLLocation Manager didStartMonitoringForRegion delegate method not called

I am trying to use location monitoring in my app. I can set my location and reverseGeocode the location I want to monitor. the didUpdateToLocation delegate method works fine, and updates continuously but the didStartMonitoingForRegion delegate never gets called, nor do the didExitRegion nor didEnterRegion.
Any suggestions?
- (IBAction)setLocation:(UIButton *)sender {
if(!self.locationManager) self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:10]; // Update again when a user moves distance in meters
[self.locationManager setPurpose:#"Set location based alerts if switch is on"];
self.plugLocation=nil; //reset to nil so didUpdateToLocation will update it
self.distanceLabel.text=[NSString stringWithFormat:#"%d",0];
[self.locationManager startUpdatingLocation];
if ( ![CLLocationManager regionMonitoringAvailable] || ![CLLocationManager regionMonitoringEnabled] ){
NSLog(#"Location monitoring not Unavailable");
}else {
}
}
-(void)setPlugLocation:(CLLocation *)plugLocation{
//
if (!_plugLocation) _plugLocation=[[CLLocation alloc]init];
_plugLocation=plugLocation;
if (_plugLocation) {
[self setRegion:plugLocation radius:20 name:self.plugName];
[self reverseGeocode:self.plugLocation];
NSLog(#"setPlugLocation %#", [self.plugLocation description]);
}
}
-(void)setRegion:(CLLocation *)center radius:(double)meters name:(NSString*)name{
CLLocationCoordinate2D plug2D;
plug2D.latitude=center.coordinate.latitude;
plug2D.longitude=center.coordinate.longitude;
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter:plug2D radius:meters identifier:name];
[self.locationManager startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyBest];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
self.latitudeLabel.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.latitude];
self.longitudeLabel.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
if (self.plugLocation == nil)self.plugLocation = newLocation;
if (self.plugLocation!=nil) {
CLLocationDistance distanceBetween = [newLocation distanceFromLocation:self.plugLocation];
NSLog(#"didUpdateToLocation Distance from plug=%f",distanceBetween);
self.distanceLabel.text=[NSString stringWithFormat:#"%f",distanceBetween];
}
}
-(void)reverseGeocode:(CLLocation *)coordinates;{
if (!self.plugGeo) self.plugGeo = [[CLGeocoder alloc] init];
[self.plugGeo reverseGeocodeLocation:coordinates completionHandler:^(NSArray *placemarks, NSError *error) {
if (error==nil&&[placemarks count]>0) {
CLPlacemark *placemark=[placemarks objectAtIndex:0];
NSLog(#" setPlugLocation geocodeAddressString %#",placemark);
//should also transfer back to plug detail and save
self.locationLabel.text=[NSString stringWithFormat:#"%# %#\n%#, %#", placemark.subThoroughfare, placemark.thoroughfare, placemark.locality,placemark.postalCode];
[self sendAlertMessage:[NSString stringWithFormat:#"%# %#\n%#, %#", placemark.subThoroughfare, placemark.thoroughfare, placemark.locality,placemark.postalCode] title:#"Success"];
}else {
NSLog(#" setPlugLocation couldn't geoCode address %#",error);
}
}];
}
Are you using the simulator to test your application? Something that I've found is that the simulator is completely unreliable for region exit/enters. Try compiling the project on your device by plugging it in and changing from iPhone Simulator to your iOS device. You can then unplug your device and run your app from your phone to test it.
Why doesn't the simulator work for regions? Regions are mostly determined by Apple's hidden algorithm using Wi-Fi, cell towers, and other applications on the phone requesting location. Seeing as a simulator doesn't use Wi-Fi or cell towers... region monitoring is going to be pretty impossible.
It's likely your code is fine (I see no glaring errors), but the simulator is giving you bad results. Try it on your device and let us know if it does the same thing.

Application crashes when requesting CLLocation property from appDelegate

I have an application which creates a class instance that contains (amongst other things) some location data.
In the app delegate I set up location services and start grabbing the location data;
//Delegate method to receive location information from locationManager
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
latestLocation = newLocation;//Make latest location the same as NewLocation
NSLog(#"Location is: %#", latestLocation);
}
I declare latest location as a property so that I can get at the CLLocation instance from another class.
My captures class, when called grabs the CLLocation when its init method is called;
//Designated initialiser
-(id) initWithVideoPath:(NSString *) vPath
userNotes:(NSString *) uNotes
retentionState:(NSString *) rState
{
//Call the super classes designated initializer
[super init];
//Get a pointer to the application delegate so we can access the location props
Rolling_VideoAppDelegate *appDelegate = (Rolling_VideoAppDelegate*)[UIApplication sharedApplication].delegate;
//If superclass failed to init
if (!self)
return nil;
//Give the variables some initial values
[self setVideoPath:vPath];
[self setUserNotes:uNotes];
[self setRetentionState:rState];
dateCreated = [[NSDate alloc] init];
mp = [[MapPoint alloc]initWithCoordinate:[[appDelegate latestLocation]coordinate]];//get the location from the coords from appDelegate
return self;
[dateCreated release];
}
However the app crashes when the mapPoint init is called. The problem is I'm not getting the CLLocation information in properly.
I'm still unsure why the original solution does not work, so if anyone has any insights please do enlighten.
I have however worked out a slightly inelegant work around using NSUserDefaults
latestLocation = newLocation;//Make latest location the same as NewLocation
//Use NSUser Defaults to save the CLLocation instance
NSUserDefaults *location = [NSUserDefaults standardUserDefaults];
[location setDouble:latestLocation.coordinate.latitude forKey:#"lat"];
[location setDouble:latestLocation.coordinate.longitude forKey:#"longd"];
I needed to break out the lat and long as NSUserDefaults will not store CLLocation objects (NSCoding compatability), the reconstruct them in the captures class;
NSUserDefaults *location = [NSUserDefaults standardUserDefaults];//Get a handle to the user defaults
CLLocationDegrees lat = [location doubleForKey:#"lat"];
CLLocationDegrees longd = [location doubleForKey:#"longd"];
CLLocation *currentLocation = [[CLLocation alloc] initWithLatitude:lat longitude:longd];
mp = [[MapPoint alloc]initWithCoordinate:[currentLocation coordinate]];//get the location from the coords from appDelegate

Resources