I have an iOS app that uses a users current location to show directions/ distance between the users current location and a destination point. I am able to show the destination point on the map, however when I try to get the user's current location using CLlocationManager, it returns coordinates (0,0). Below is my code for retrieving the users location.
Is retrieving current location possible on the Apple Watch?
If so, what am I doing wrong here that the location is returning (0,0)?
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.distanceFilter = 5;
CLLocation *location = locationManager.location;
CLLocationCoordinate2D myLoc = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
Also, I have #import < CoreLocation/CoreLocation.h> in my .h file and < CLLocationManagerDelegate>
Try the following code:
#property (nonatomic, strong) CLLocationManager *locationManager;
- (void)willActivate
{
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self];
[self.locationManager requestLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
if ([locations count] == 0) {
// error
return;
}
// success
self.currentLocation = [locations firstObject];
CLLocationCoordinate2D myLoc = CLLocationCoordinate2DMake(
self.currentLocation.coordinate.latitude,
self.currentLocation.coordinate.longitude);
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(nonnull NSError *)error
{
// error
}
If you did not implemented this:
(with attributes inspector or programmatically)
self.mapView.showsUserLocation = YES
Or in addition to tell the mapView that the user's location is depending of LocationManager.location
Related
This question already has answers here:
How to find your current location with CoreLocation
(3 answers)
Closed 6 years ago.
I am working in google map in my app. i get default location on map currently. but i need to get current location of device an show it on map. There are lots of solution are there on stackoverlfow, but somehow its not working in my case. These solution work if i add map on default view.Look at my little bit code.
.h file
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import GoogleMaps;
#interface ViewController : UIViewController<CLLocationManagerDelegate, GMSMapViewDelegate>
#property (weak, nonatomic) IBOutlet UIView *maponScreem;
#property (nonatomic, retain) CLLocationManager *locationManager;
#end
.m file
self.locationManager.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[self.locationManager startUpdatingLocation];
latitude = [NSString stringWithFormat:#"%f",self.locationManager.location.coordinate.latitude];
longtitude = [NSString stringWithFormat:#"%f",self.locationManager.location.coordinate.longitude];
NSLog(#"%#", latitude);
NSLog(#"%#", longtitude);
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:[latitude floatValue]
longitude:[longtitude floatValue]
zoom:12];
mapView_ = [GMSMapView mapWithFrame:self.maponScreem.bounds camera:camera];
mapView_.delegate = self;
mapView_.myLocationEnabled = YES;
[self.maponScreem addSubview: self->mapView_];
// Creates a marker in the center of the map.
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake([latitude intValue], [longtitude intValue]);
marker.title = #"Current Location";
marker.map = mapView_;
i get 0.000000 for attitude and longitude.
EDIT:
i found solution and look at this how it works. Thanks to you all for answers and support me.
- (void)viewDidLoad {
[super viewDidLoad];
if (self.locationManager == nil)
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
}
else
{
nil;
}
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
else
{
nil;
}
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithTarget:CLLocationCoordinate2DMake(0, 0) zoom: 16];
mapView_ = [GMSMapView mapWithFrame:self.maponScreem.bounds camera:camera];
mapView_.myLocationEnabled = YES;
[self.maponScreem addSubview: self->mapView_];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
NSString *lasti = [NSString stringWithFormat:#"%f", location.coordinate.latitude];
NSString *longi = [NSString stringWithFormat:#"%f", location.coordinate.longitude];
// NSLog(#"%#", lat);
// NSLog(#"%#", longi);
[mapView_ animateToLocation:location.coordinate];
}
You have not initialized your locationManager and also you need to ask user permission for location access and set its delegate.Use following code before starting location updates.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization]; //gives alert for location access
}
It will give you user location.
Hope it helps :)
EDIT
You should use below method to receive location updates
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations
The method you have used is deprecated.
#property (nonatomic, retain) IBOutlet GMSMapView *googleMapView;
#property (nonatomic, retain) CLLocationManager *locationManager;
- (void)showCurrentLocation {
_googleMapView.myLocationEnabled = YES;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:newLocation.coordinate.latitude
longitude:newLocation.coordinate.longitude
zoom:17.0];
[_googleMapView animateToCameraPosition:camera];
//...
}
I hope this will help you..
- (IBAction)btnSetDistance:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.pausesLocationUpdatesAutomatically = NO;
locationManager.distanceFilter =//as per your requirment;
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
}
This is important
Enable Background Modes from--- Project, Capabilities Tab, and choose Location Updates...
you should check it on device instead of simulator.
UPDATED for iOS9: I am new to iOS, experimenting with CoreLocation to return latitude and longitude values. The following code never executes the log output
-(void)viewWillAppear:(BOOL)animated{
manager = [[CLLocationManager alloc]init];
manager.delegate = self;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation];
}
Here is my didUpdateToLocation function with is never reached
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations{
NSLog(#"Location: %#", locations);
CLLocation *currentLocation = locations.lastObject;
if (currentLocation != nil) {
float latitude = currentLocation.coordinate.latitude;
float longitude = currentLocation.coordinate.longitude;
NSLog(#"dLongitude : %f", longitude);
NSLog(#"dLatitude : %f", latitude);
}
else{ NSLog(#"ERROR");
}
}
CLLocationManager is asynchronous, You should get the latitude and longitude in the delegate method.
locationManager.delegate = self;
Then implement this delegate method:
- locationManager:didUpdateLocations:
1.first of all, you should use you should use a actual device instead of a simulator
2.implement CLLocationManagerDelegate in the interface,like
#interface XXXXX () <CLLocationManagerDelegate>
3.after
locationManager = [[CLLocationManager alloc] init];
add
locationManager.delegate = self;
4.implement the delegate method
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
for (CLLocation *location in locations) {
//you can get locations here
}
}
I am a iOS application developer. I am working with Location Manager.
For every 5 seconds I am capturing the latitude and longitude and storing the CLLocation object in array. The lat and long is not completely correct when I am trying to draw those location in Map.
My code is following below:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{//ios6&+
CLLocation *loc;
NSInteger objCount = [locations count];
if (objCount >= 1) {
loc = [locations objectAtIndex:objCount - 1];
NSArray *Arr_TotalTime = [Str_TotalTime componentsSeparatedByString:#":"];
[ArrayOfLocations addObject:loc];
}
}
Any one can please give me more info to get ACTUAL location (lat, long) from didupdatelocation method.
Any help will be highly appreciated.
Depending on how you set up your location manager, the accuracy will vary.
Try something like this:
Location Manager
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
_locationManager.activityType = CLActivityTypeAutomotiveNavigation;
_locationManager.distanceFilter = kCLDistanceFilterNone;
Method
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
NSDate *eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if ((abs(howRecent) <= 5) && (newLocation.horizontalAccuracy > 0) && (newLocation.verticalAccuracy > 0) && (newLocation.horizontalAccuracy < 100) && (newLocation.verticalAccuracy < 100))
{
[ArrayOfLocations addObject:newLocation];
}
else
{
// received bad signal
}
}
You can use CoreLocation to get the longitude and latitude.
Include framework:
Click your project in navigator.
Click the plus button under "link binary with libraries"
Add Corelocation to your project.
Import the header file:
import
Declare CLLocationManager:
CLLocationManager *locationManager;
initialize locationManager:
- (void)viewDidLoad
{
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
}
Then, use
float latitude = locationManager.location.coordinate.latitude;
float longitude = locationManager.location.coordinate.longitude;
This my code......
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
location_updated = [locations lastObject];
NSLog(#"updated coordinate are %#",location_updated);
latitude1 = location_updated.coordinate.latitude;
longitude1 = location_updated.coordinate.longitude;
self.lblLat.text = [NSString stringWithFormat:#"%f",latitude1];
self.lblLon.text = [NSString stringWithFormat:#"%f",longitude1];
NSString *str = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=false",latitude1,longitude1];
url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
connection = [NSURLConnection connectionWithRequest:request delegate:self];
if (connection)
{
webData1 = [[NSMutableData alloc]init];
}
GMSMarker *marker = [[GMSMarker alloc] init];
marker.position = CLLocationCoordinate2DMake(latitude1,longitude1);
marker.title = formattedAddress;
marker.icon = [UIImage imageNamed:#"m2.png"];
marker.map = mapView_;
marker.draggable = YES;
}
This method is call multiple times which i don't want.....
While allocating your LocationManager object you can set the distanceFilter property of the LocationManager. Distance filter property is a CLLocationDistance value which can be set to notify the location manager about the distance moved in meters. You can set the distance filter as follows:
LocationManager *locationManger = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = 100.0; // Will notify the LocationManager every 100 meters
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
The easiest way:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
[manager stopUpdatingLocation];
manager.delegate = nil;
//...... do something
}
The manager can't find your didUpdateLocations method without the delegate reference :-D
But don't forget to set it again before using startUpdatingLocation
Add some restriction there. For timespan between locations and accuracy
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = locations.lastObject;
NSTimeInterval locationAge = -[newLocation.timestamp timeIntervalSinceNow];
if (locationAge > 5.0) return;
if (newLocation.horizontalAccuracy < 0) return;
// Needed to filter cached and too old locations
//NSLog(#"Location updated to = %#", newLocation);
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:_currentLocation.coordinate.latitude longitude:_currentLocation.coordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
double distance = [loc1 distanceFromLocation:loc2];
if(distance > 20)
{
_currentLocation = newLocation;
//significant location update
}
//location updated
}
I have similar situation. You can use dispatch_once:
static dispatch_once_t predicate;
- (void)update
{
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
[_locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[_locationManager requestWhenInUseAuthorization];
}
_locationManager.delegate = self;
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
predicate = 0;
[_locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
[manager stopUpdatingLocation];
manager = nil;
dispatch_once(&predicate, ^{
//your code here
});
}
locationManager.startUpdatingLocation() fetch location continuously and didUpdateLocations method calls several times,
Just set the value for locationManager.distanceFilter value before calling locationManager.startUpdatingLocation().
As I set 200 meters(you can change as your requirement) working fine
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 200
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
You can use a static variable to store the latest location timestamp and then compare it to the newest one, like this:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
[manager stopUpdatingLocation];
static NSDate *previousLocationTimestamp;
CLLocation *location = [locations lastObject];
if (previousLocationTimestamp && [location.timestamp timeIntervalSinceDate:previousLocationTimestamp] < 2.0) {
NSLog(#"didUpdateLocations GIVE UP");
return;
}
previousLocationTimestamp = location.timestamp;
NSLog(#"didUpdateLocations GOOD");
// Do your code here
}
Swift 5 :
If you are looking for a solution in swift.
I tried the accepted answer but it didn't work for me. I tried the below solution by checking the time duration between locations. if it is less than 10 seconds then it will return and the location handler will not update.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else {
return
}
let locationAge = -location.timestamp.timeIntervalSinceNow
if locationAge > 10.0 { //10 seconds
return
}
if location.horizontalAccuracy < 0 {
return
}
self.currentLocation = location
print("Location :- \(location.coordinate)")
//location updated
}
Write this method when ever you want to stop updating location manager
[locationManager stopUpdatingLocation];
for the time constraint, i did not understand code from accepted answer, posting a different approach. as Rob points out "When you first start location services, you may see it called multiple times". the code below acts on the first location, and ignores the updated locations for first 120 seconds. it is one way to address orginal question "How to stop multiple times method calling of didUpdateLocations".
in .h file:
#property(strong,nonatomic) CLLocation* firstLocation;
in .m file:
// is this the first location?
CLLocation* newLocation = locations.lastObject;
if (self.firstLocation) {
// app already has a location
NSTimeInterval locationAge = [newLocation.timestamp timeIntervalSinceDate:self.firstLocation.timestamp];
NSLog(#"locationAge: %f",locationAge);
if (locationAge < 120.0) { // 120 is in seconds or milliseconds?
return;
}
} else {
self.firstLocation = newLocation;
}
// do something with location
You could set a flag (Bool). When you instantiate your locationsManager set flag = true then when locationManager:didUpdateLocations returns inside a code block
that you want to run only once set flag = false. This way it will only be run the once.
if flag == true {
flag = false
...some code probably network call you only want to run the once
}
locations manager will be called multiple times but the code you want to execute only once, and I think that is what you are trying to achieve?
you can write :
[manager stopUpdatingLocation];
manager = nil;
in didupdatelocation delegate
A few things worked for me:
setting location manager nil while didUpdateLocations after calling manager.stopUpdatingLocation()
I will suggest setting the location manager to nil is not a good approach.because CLLocationManager sometimes give accurate location in 3-4 times.
What I will suggest change accuracy to kilometers that's worked for me
clLocationManager?.distanceFilter = 1000
clLocationManager?.desiredAccuracy = kCLLocationAccuracyKilometer
- (IBAction)getdirections:(id)sender {
directionview=[[directionViewController alloc]initWithNibName:#"directionViewController" bundle:nil];
directionview.sourceplace=user.location;
[self.view addSubview:directionview.view];
}
I want to store the user's locations in "sourceplace" which is a NSString type variable in another view controller named "directionViewController".
I am fetching data in variable "user" from and i tried NSLogging user and i can see that it has the "location" key.
In your .h :
#import <CoreLocation/CoreLocation.h>
#interface yourController : UIViewController <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
NSString *str;
}
In your .m :
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
You can convert location to string from location like this:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
str=[[NSString alloc] initWithFormat:#" latitude:%f longitude:%f", location.coordinate.latitude, location.coordinate.longitude];
NSLog(#"%#",str);
}
after
if your directionview.sourceplace is a NSString too:
directionview.sourceplace = str;