I need to know if an instance of CLLocationManager (in this case called gps) is updating location calling the proper method
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
In my case the complete method is:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
//NSLog(#"didUpdateToLocation: %#", newLocation);
currentLocation = newLocation;
if (currentLocation != nil) {
longitude.text = [NSString stringWithFormat:#"%.3f", currentLocation.coordinate.longitude];
latitude.text = [NSString stringWithFormat:#"%.3f", currentLocation.coordinate.latitude];
}
address.text = NULL;
[activityIndicator setHidden:NO];
[activityIndicator startAnimating];
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
//NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
[address sizeToFit];
address.text = [NSString stringWithFormat:#"%#, %#\n%# %#\n%#",
[self sanitizedDescription:placemark.thoroughfare],
[self sanitizedDescription:placemark.subThoroughfare],
[self sanitizedDescription:placemark.postalCode],
[self sanitizedDescription:placemark.locality],
[self sanitizedDescription:placemark.country]];
if (address.text != NULL)
{
gpsTimer = [NSTimer scheduledTimerWithTimeInterval:10
target:gps
selector:#selector(startUpdatingLocation)
userInfo:nil
repeats:NO];
[address sizeToFit];
[gps stopUpdatingLocation];
}
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
How can I do?
Thanks in advance :)
subclass your CLLocationManager and add a BOOL that is set to yes when your delegate method gets called...
You can also simply tell your location manager to stop within the delegate method
Below is a simple example code to show how to deal with this issue.
import Foundation
import CoreLocation
public class LocationManager : NSObject, CLLocationManagerDelegate{
var locationManager: CLLocationManager?
public var isLocationUpdate: Bool = false
override public init() {
super.init()
self.locationManager = CLLocationManager()
self.locationManager!.delegate = self
if #available(iOS 9.0, *) {
self.locationManager!.requestWhenInUseAuthorization()
}
self.locationManager!.startUpdatingLocation()
self.isLocationUpdate = false
}
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.isLocationUpdate = true
print(locations)
}
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
//Retrieving the error code.
if let code = (error as NSError).code{
isLocationUpdate = false
}
}
Apple deprecated one of the primary location manager delegate methods in iOS 6, so if you are supporting older versions of iOS as well as the current version, you will need to include support for both delegate methods:
iOS 2 - iOS 5:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
iOS 6 and later:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
There really is no way for you to check "is my delegate 'active' for this locationmanager?".
What you need to do is keep track yourself of whether you're done with the location updates.
I'm not sure if this is what you need, but here's what i do:
1- when i start requesting updates, i do as you do, i.e. through requestlocationupdates and a delegate.
2- In the case where i don't get the updates i need, i want to time out after some time, so that my app doesn't wait for a location forever, in this case i use a Selector with a timeout:
[self performSelector:#selector(fetchLocationTimeout) withObject:nil afterDelay:LOCATION_LISTEN_TIME];
and in the selector:
(void)fetchLocationTimeout{
if(!finished){
[self stopUpdatingLocation];
[delegate locationFinished:bestEffortAtLocation];//see more on this below
}
}
3- in my didupdate-delegate i both store away the "best" location i have gotten, and if i decide that the new location is "good enough", i finish my location-fetching process:
(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
if(newLocation is the best i have){
self.bestEffortAtLocation = newLocation;
}
// test the measurement to see if it is more accurate than the previous measurement
if (bestEffortAtLocation == nil || newLocation is the best i have) {
// store the location as the "best effort"
if (bestEffortAtLocation is good enough and i want to use it) {
[self stopUpdatingLocation];
// we can also cancel our previous performSelector:withObject:afterDelay: - it's no longer necessary
SEL selector = NSSelectorFromString(#"fetchLocationTimeout");
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:selector object:nil];
[delegate locationFinished:bestEffortAtLocation];
}
}
}
Finally, this is my method which is called above, both from within the didupdate-delegate and from the selector timeout to reduce the risk of a race condition:
(void)stopUpdatingLocation{
finished = true;
NSLog(#"stopUpdatingLocation! manager: %#", [locationManager description]);
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
}
Final note: the "delegate" i'm calling when i'm done is my own interface describing a class that knows how to take care of the result of a location-fetching process. it has only one method to be implemented "locationFinished", as you can see.
Hope this helps even though my code-pasting skills aren't exactly ninja.
Related
I'm trying to implement longitude and latitude in my sample app. I use iPhone 5s device to test it. It doesn't show any effect on latitude and longitude labels on button actions.
Before compiling Xcode shows warning at line didUpdateToLocation: fromLocation: method as
"implementing deprecated method"
please help me with the suitable method which replaces this method for smooth working of the app
With Xcode 12.4 and for iOS 12.3 using objective c I'm trying to implement a simple location demo app which shows longitude and latitude. Below are my viewController.h and viewController.m files. And I've tried this below code from online tutorial AppCoda
viewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController :UIViewController<CLLocationManagerDelegate>
{
IBOutlet UILabel *lattitudeLabel;
IBOutlet UILabel *longitudeLabel;
IBOutlet UILabel *addressLabel;
}
- (IBAction)getCurrentLocation:(UIButton *)sender;
#end
viewController.m
#import "ViewController.h"
#interface ViewController ()
{
CLLocationManager *locationManager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc]init];
geocoder = [[CLGeocoder alloc] init];
}
- (IBAction)getCurrentLocation:(UIButton *)sender
{
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
NSLog(#"Error: Failed to get location");
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
longitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
lattitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
[locationManager stopUpdatingLocation];
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
self->placemark = [placemarks lastObject];
self->addressLabel.text = [NSString stringWithFormat:#"%# %#\n%# %#\n%#\n%#",
self->placemark.subThoroughfare, self->placemark.thoroughfare,
self->placemark.postalCode, self->placemark.locality,
self->placemark.administrativeArea,
self->placemark.country];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
#end
On clicking button get my location nothing is happening. It should actually update the co-ordinates besides Longitude: and Latitude: some float values..but it's not doing that..I'll ask please suggest me links to any tutorial web site or any GitHub project for location handling in iOS 12.3 and above in objective c...Thanks for the replies and suggested edits.
As the docs say, just use locationManager(_:didUpdateLocations:)
.
Swift 5
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Stop updates if this is a one-time request
manager.stopUpdatingLocation()
// Pop the last location off if you just need current update
guard let newLocation = locations.last else { return }
<... Do something with the location ...>
}
Objective-C
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
[manager stopUpdatingLocation];
CLLocation *newLocation = [locations lastObject];
if (newLocation) {
<... Do something with the location ...>
}
}
I hope this implementation for delegate method will help you.
works both on Mac and IOS. I used it to pinpoint current position for weather application.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations
{
if (locations.count > 0) {
// Location manager has nonempty array of readings
// We take the las one - the latest position determined
CLLocation *last = locations[locations.count - 1];
// Evaluate threshold distance to notice change
CLLocationDistance distance = LOCATOR_SENSITIVITY + 1;
if (previous) {
// calculate distance from previous location
distance = [last distanceFromLocation:previous];
}
// update previous location
previous = last;
if (distance > LOCATOR_SENSITIVITY) {
// If we moved far enough, update current position
currentLat = last.coordinate.latitude;
currentLon = last.coordinate.longitude;
// and notify all observers
// You can use delegate here, dispatch_async wrapper etc.
[[NSNotificationCenter defaultCenter]
postNotificationName:LocationIsChanged object:nil];
}
}
}
I recently asked this question, not knowing of the changes made to CL in iOS 9. I am trying to store the user's current location and I have changed my code to reflect the new delegate methods in iOS 9, but didUpdateLocations is still never reached.
Here is the link to my original question: Latitude & Longitude Not Retrieved
And my updated code:
viewWillAppear
- (void)viewWillAppear:(BOOL)animated{
manager = [[CLLocationManager alloc] init];
manager.delegate = self;
if ([manager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[manager requestWhenInUseAuthorization];
}
[manager startUpdatingLocation];
}
didUpdateLocations
- (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");
}
}
check for
authorizationStatus and startUpdatingLocation
and
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
you can also go to settings ->privacy -> location services (turn on) -> select ur app and select while using.
EDIT: Ok, I just have noticed that the problem is exclusive of iOS 7. I'm still being unable to solve it, however, so I suppouse I'll try with the sugestions bellow. Thanks to all!
¡Hi! I'm programming a navigator app, and I need to update the user position whenever is possible. I have two View Controllers that use CLLocation manager. In both of them I've added this line:
#import <CoreLocation/CoreLocation.h>
And then added the to the interface declaration, and I'm setting this as a property in the .h file, and synthetizing afterwards:
#property (strong, nonatomic) CLLocationManager *locationManager;
After that, I'm launching de locationManager in the viewDidLoad, this way:
if(self){
locationManager = [[CLLocationManager alloc] init];
//locationManager.delegate = self;
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLHeadingFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[locationManager startUpdatingLocation];
}
And here are my delegate methods.
For the first View:
#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) {
homeLatitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude] doubleValue];
homeLongitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude] doubleValue];
NSLog(#"Updated! -> hl = %f, hlg = %f", homeLatitude, homeLongitude);
}
}
For the second view. As you can see, I replaced the old didUpdateToLocation with didUpdateLocations, as a desperate try.
#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) {
NSLog(#"Tarzan boy");
_testLabel.text = [NSString stringWithFormat:#"Oh DAMN!!!!"];
}
}*/
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(#"didUpdateToLocation: %#", [locations lastObject]);
CLLocation *currentLocation = [locations lastObject];
if (currentLocation != nil) {
currentLatitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude] doubleValue];
currentLongitude = [[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude] doubleValue];
NSLog(#"Updated! (MapWithRoutesViewController) -> hl = %f, hlg = %f", currentLatitude, currentLongitude);
_testLabel.text = [NSString stringWithFormat:#"Update! -> hl = %f, hlg = %f", currentLatitude, currentLongitude];
//Aquí es donde borramos el lugar al que llegaron.
if(mapView){
if(followMe){
CLLocationCoordinate2D *c = &((CLLocationCoordinate2D){.latitude = currentLatitude, .longitude = currentLongitude});
[mapView.mapView as_setCenterCoordinate:*c zoomLevel:32 animated:NO];
_ourStepper.value = [mapView.mapView as_zoomLevel];
}
if([mapView getNearestDestinyDistance:currentLocation] < 150.0){
NSLog(#"Hay que eliminar el primer destino del MapView");
mapView.destinoActual++;
}
if([mapView getNearestPointDistance:currentLocation] > 200.0){
NSLog(#"Hay que recalcular la ruta al destinoActual");
SpinnerView *spinner = [SpinnerView loadSpinnerIntoView:self.view];
spinner.tag = 98;
while (![mapView recalculateRoutesTo:currentLocation]) {
//do nothin...
}
[spinner removeSpinner];
}
}
}
//[locationManager stopUpdatingLocation];
}
As you can see, the line
//[locationManager stopUpdatingLocation];
is commented. Well, the problem is driving me crazy is that the code above works as a charm in the first view controller, and update periodically as I expected. But in the second view, it works only the first time, and never updates again. I programmed these methods in different times, so I can't remember if I did something to the first view I didn't to the second. But they are in the same app, so I assume there's no problem with libraries or permissions. Any help or hint is welcome, thanks!
First off, if you are doing navigation, you should be registering for significant change notifications. Go read the documentation on that here. It's much more efficient. You will have to turn it off when you are not using it, but it's much better. Support for it goes all the way back to iOS 4. That's 99% of the user population for sure.
I had a similar situation in my application and implemented a singleton that handles all location updates and then fires off NSNotificaitons to the foreground threads.
Create a singleton class that handles the location updates View would
register to listen to LOCATION_CHANGE updates perhaps Background
singleton object registers as the delegate for the location manager
This may not be the answer you are looking for but i know it worked in my case.
Found the solution here. The locationManager works when I launch it this way:
if(self){
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLHeadingFilterNone];
//change the desired accuracy to kCLLocationAccuracyBest
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//SOLUTION: set setPausesLocationUpdatesAutomatically to NO
[locationManager setPausesLocationUpdatesAutomatically:NO];
[locationManager startUpdatingLocation];
}
I'll work anyway in performance like Rob suggested. Thanks to all for the help!
I want to get users current location(lat,long) on the app launch only..i dont want to use delegate method for frequent location updates..I m not using maps just need current location on launch..how should i do this??
I am using the code below but its not working.
CLLocationManager *locationManager;
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyBest;
locationManager.distanceFilter=kCLDistanceFilterNone;
[locationManager startUpdatingLocation];
CLLocation *location;
location = [locationManager location];
CLLocationCoordinate2D coord;
coord.longitude = location.coordinate.longitude;
coord.latitude = location.coordinate.latitude;
NSLog(#"latitude %f longitude %f",coord.latitude,coord.longitude);
Output:-
latitude 0.000000 longitude 0.000000
please help..
better you use the delegate method to get user location and in didupdateLocation method stop it
I think this url may help you
iPhone SDK: Track users location using GPS
and in
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
CLLocationCoordinate2D here = newLocation.coordinate;
NSLog(#"%f %f ", here.latitude, here.longitude);
[locationManager stopUpdatingLocation];
}
and you done with it...
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
// Reverse Geocoding
// NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
// NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
[locationManager stopUpdatingLocation];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
Use CLLocationManagerDelegate method
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
[_locationManager stopUpdatingLocation];
NSLog(#"latitude %f longitude %f",newLocation.coordinate.latitude,,newLocation.coordinate.longitude);
}
Above method is deprecated in iOS6, use locationManager:didUpdateLocations: instead
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
import <CoreLocation/CoreLocation.h>
delegate: CLLocationManagerDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// System alert for Allowing current location of user.
// Location manager object creation.
locationManager = [[CLLocationManager alloc] init];`enter code here`
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
// iOS >= 6.0.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
[locationManager stopUpdatingLocation];
}
// iOS < 6.0
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[locationManager stopUpdatingLocation];
}
I have the following code:
- (void) viewWillAppear {
[self startSignificantChangeUpdates];
}
- (void)startSignificantChangeUpdates
{
if ([CLLocationManager locationServicesEnabled])
{
NSLog(#"start significant changes");
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startMonitoringSignificantLocationChanges];
}
}
problem is that the location manage is not calling its delegate function
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
What can I do?
In your .h file:
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate>
In your .m file:
#implementation ViewController {
// This is a private variable, used within this file only
CLLocationManager *locationManager;
}
-(void)viewDidLoad {
locationManager = [[CLLocationManager alloc] init];
}
-(void)viewWillAppear {
// If the delegate is still not being set, try putting this code into viewDidAppear
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
-(void)locationManger:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"didFailWithError: %#", error);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(#"didUpdateToLocation: %#", [locations lastObject]);
CLLocation *currentLocation = [locations lastObject];
[locationManager stopUpdatingLocation];
}
For more information about getting the user's location, look at this guide, which I used to implement location into an app of mine: http://www.appcoda.com/how-to-get-current-location-iphone-user/
How are you testing this? If you are running this in the simulator, you can go to Debug->Location->Freeway Drive. You can put a break point in locationManager:didUpdateToLocation method or even put a log statement to log the current location coordinates. You should see it work.
Please replace this line
[locationManager startMonitoringSignificantLocationChanges];
with this code
[locationController.locationManager startUpdatingLocation];
and then check
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
}