I was asked to code a small app for iOS in Objective C that's supposed to choose the closest object of a user, in a set of coordinates
The plan was to load the coordinates of the user only once, when the application loads for the first time.
Here's my current code :
(void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.headingFilter = 1;
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[self.locationManager startUpdatingLocation];
self.userLat = self.locationManager.location.coordinate.latitude;
self.userLon = self.locationManager.location.coordinate.longitude;
NSLog(#" ----------------------------- ");
NSLog(#"User lat : %lf", self.userLat);
NSLog(#"User lon : %lf", self.userLon);
NSLog(#" ----------------------------- ");
}
I don't have a Apple iOS developper program, so I'm stuck with the iOS simulator from xCode.
I try to set some custom coordinates in the iOS simulator through debug, like this :
When i execute the app (obviously after setting coordinates), the log has userLat and userLon to 0.00..
Apr 6 03:16:20 Locals-Mac.local app[5683]: -----------------------------
Apr 6 03:16:20 Locals-Mac.local app[5683]: User lat : 0.000000
Apr 6 03:16:20 Locals-Mac.local app[5683]: User lon : 0.000000
Apr 6 03:16:20 Locals-Mac.local app[5683]: -----------------------------
I remember hearing somewhere that the iOS simulator don't work with the CoreLocation library (It might be right or wrong, i wouldn't know).
Is it the reason the lat/lon values are 0?
If the reason is indeed the iOS simulator, does this code give user current location?
Thanks in advance!
Edit :
With the answer and comments, i'm now using the didUpdateLocations callback function :
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
self.userLat = location.coordinate.latitude;
self.userLon = location.coordinate.longitude;
NSLog(#" ----------------------------- ");
NSLog(#"User lat : %lf", self.userLat);
NSLog(#"User lon : %lf", self.userLon);
NSLog(#" ----------------------------- ");
}
I ask xCode to simulate my position to London with the Scheme option that follows :
My new load function :
-(void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.headingFilter = 1;
self.locationManager.delegate = self;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
[self.locationManager requestWhenInUseAuthorization];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[self.locationManager startUpdatingLocation];
}
This code still doesn't print the NSLog that was put in the location callback function. Did i miss something?
The location manager doesn't instantly have the user's location when you start updating it. If you check the location property right after calling startUpdatingLocation it is usually going to be nil unless some other app was recently updating it. You need to implement the locationManager:didUpdateLocations: delegate method which will be called once it has a location.
You also need to check and possibly request for location permissions.
Related
In my current project.
I need user's location at every 50 meter user move.
So Basically After open application every 50 meter change I need user location for call web service in Objective c. Also i want same process run when application is in background state.
Thanks in advance
You have to make object of CLLocationManager when application starts and set it's delegate
Add the below code to get user's current location
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
Now add the delegate of CLLocationManagaer that is didUpdateToLocation and add the following code in that.
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
if(meters==50)
{
// CALL YOU WEBSERVICE
}
set your location track in
//create location manager object
locationManager = [[CLLocationManager alloc] init];
//there will be a warning from this line of code
[locationManager setDelegate:self];
//and we want it to be as accurate as possible
//regardless of how much time/power it takes
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//set the amount of metres travelled before location update is made
[locationManager setDistanceFilter:50];
and add
if ([CLLocationManager locationServicesEnabled]) {
[self.locationManager startUpdatingLocation];
}
Update
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = locations.lastObject;
NSLog(#"%#", location.description);
//In here you get all details like
NSLog(#"latitude = %#",location.coordinate.latitude);
NSLog(#"longitude = %#",location.coordinate.longitude);
NSLog(#"altitude = %#",location.altitude);
NSLog(#"horizontalAccuracy = %#",location.horizontalAccuracy);
NSLog(#"verticalAccuracy = %#",location.verticalAccuracy);
NSLog(#"timestamp = %#",location.timestamp);
NSLog(#"speed = %#",location.speed);
NSLog(#"course = %#",location.course);
}
I am using iOS8 and using the following code for getting longitude and latitude by GPS:
-(void)CurrentLocationIdentifier
{
locationManager = [CLLocationManager new];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 &&
[CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse)
//[CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedAlways)
{
// Will open an confirm dialog to get user's approval
[locationManager requestWhenInUseAuthorization];
//[_locationManager requestAlwaysAuthorization];
} else {
[locationManager startUpdatingLocation]; //Will update location immediately
}
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
NSLog(#"lat%f - lon%f", location.coordinate.latitude, location.coordinate.longitude);
}
- (void)locationManager:(CLLocationManager*)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
case kCLAuthorizationStatusNotDetermined: {
NSLog(#"User still thinking..");
}
case kCLAuthorizationStatusDenied: {
NSLog(#"User hates you");
} break;
case kCLAuthorizationStatusAuthorizedWhenInUse:
case kCLAuthorizationStatusAuthorizedAlways: {
[locationManager startUpdatingLocation]; //Will update location immediately
} break;
default:
break;
}
}
After running this code I am getting the output at log is : User still thinking. Can anyone help me with this I am new to iOS and CoreLocation.Framework ?
Please help me in finding the Error and how can I solve that.
Add this string in InfoPlist.strings files
1) NSLocationWhenInUseUsageDescription
2) NSLocationAlwaysUsageDescription
Try this code
locationManagerApp=[[CLLocationManager alloc] init];
locationManagerApp.delegate = self;
locationManagerApp.distanceFilter = kCLDistanceFilterNone;
locationManagerApp.desiredAccuracy = kCLLocationAccuracyHundredMeters;
if([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[locationManagerApp requestAlwaysAuthorization];
}
[locationManagerApp startUpdatingLocation];
CLLocation *location1 = [locationManagerApp location];
CLLocationCoordinate2D coordinate = [location1 coordinate];
self.latValue= [NSString stringWithFormat:#"%f", coordinate.latitude];
self.longValue = [NSString stringWithFormat:#"%f", coordinate.longitude];
NSLog(#"Latitude = %#", self.latValue);
NSLog(#"Longitude = %#", self.longValue);
And run project in device.
In iOS 8 you need to do two extra things to get location working: Add a key to your Info.plist and request authorization from the location manager asking it to start. There are two Info.plist keys for the new location authorization. One or both of these keys is required. If neither of the keys are there, you can call startUpdatingLocation but the location manager won’t actually start. It won’t send a failure message to the delegate either (since it never started, it can’t fail). It will also fail if you add one or both of the keys but forget to explicitly request authorization.
So the first thing you need to do is to add one or both of the following keys to your Info.plist file:
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
Both of these keys take a string which is a description of why you need location services. You can enter a string like “Location is required to find out where you are” which, as in iOS 7, can be localized in the InfoPlist.strings file.
I've just updated to Xcode 6/iOS 8 SDK and my location service simulation in simulator started not working. It was fine before I updated (I'm currently unable to test on real device). Now, when I select a location for simulation, nothing happens. Delegate's -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations method is not called. I've restarted Xcode, cleaned the build folder, nothing changed. Why can this happen?
Since IOS 8 you need to ask for authorization before starting the CLLocationManager.
Are you calling one of these methods?
[self.locationManager requestWhenInUseAuthorization]; // For foreground access
[self.locationManager requestAlwaysAuthorization]; // For background access
If you have created the project before XCode 6, you probably also need to add the info.plist entry for the new permission.
For more details have a look at this post: Location Services not working in iOS 8
Add Below code in your method
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
Also add Below line at your info.plist file
Key:NSLocationWhenInUseUsageDescription value:Uses current location
Using Xcode 6.3.1 I have had the location selection stop updating. The fix was to run another project, select "Simulate location > Don't Simulate Location" then build the original project again to resume normal location setting.
- (void)startLocationUpdates{
geocoder = [[CLGeocoder alloc] init];
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{
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
}
// Reverse Geocoding
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
fullAddress = [NSString stringWithFormat:#"%#,%#,%#,%#",
placemark.thoroughfare,
placemark.locality,
placemark.administrativeArea,
placemark.country];
subtitleLocation = [NSString stringWithFormat:#"PostalCode::%#",
placemark.postalCode];
} else {
// NSLog(#"%#", error.debugDescription);
}
} ];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error{
NSLog(#"Cannot find the location.");
}
The other answers are correct, but I also had to reset the simulator before I could get a location, whereas it was working fine on a device. The app was initially installed on that simulator before iOS 8.
To reset your simulator :
https://stackoverflow.com/a/16195931
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.
I have a CoreLocation manager in VC, when user pressed "get direction" button, I initalize location manager, and app opens google map direction with current location and some pre defined destination location.
Here is my problem, if app is not in background state, current location nearly always true, bu if app calling from background in same VC and user pressed again "get direction" button , current location generally shows old locations. In short, I'm troubling with multitasking and timestamp of retrieved locations did not solved my problem.
IBAction:
if ( self.locationManager ) {
[_locationManager release];
self.locationManager = nil;
}
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationTimer = [NSTimer scheduledTimerWithTimeInterval:LOCATION_TIMER target:self selector:#selector(stopUpdatingLocationTimer) userInfo:nil repeats:NO];
HUD = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
[self.locationManager startUpdatingLocation];
Core Location Delegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
NSLog(#"%f",locationAge);
if (locationAge > 3.0)
return;
if (newLocation.horizontalAccuracy < 0)
return;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy ) {
self.currentLocation = newLocation;
if (self.currentLocation.horizontalAccuracy <= self.locationManager.desiredAccuracy) {
[self stopUpdatingLocations:YES];
}
}
}
In your example locationAge is a negative representation of the number of seconds since the timestamp of newLocation. This means that locationAge will never be greater than 3 and you're effectively letting every update through the sieve.
Set locationAge like this:
NSTimeInterval locationAge = [newLocation.timestamp timeIntervalSinceNow];
For those who encounter same problem,
Also, some tutorials related with core location on web, lead me this problem.
Of course, I keep CLLocation ivar in my VC, whenever CLLocation ivar
sets and google maps called, my app goes to background.
Then, my app calls from background by user, and start updating locations,
and old CLLocation ivar is not nil and probably best horizantal accuracy then
newly comes. Therefore;
if ( self.currentLocation == nil || self.currentLocation.horizontalAccuracy > newLocation.horizontalAccuracy )
this line cause problems, and old location in CLLocation ivar
never replaced.
So I changed viewDidDisappear like this and I assigned nil value to CLLocation variable and works perfectly.
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.locationManager stopUpdatingLocation]; // CLLocationManager
self.locationManager = nil;
[self.locationTimer invalidate]; // NSTimer
self.locationTimer = nil;
self.currentLocation = nil; // CLLocation
}
p.s : thank you Mark Adams